【线程】 并发 、并行、进程、线程

并发:指两个或多个事件在同一时间段内发生。

并行:指两个或多个事件在同一时刻发生。

 

进程:指一个内存中运行的应用程序,每个进程都有独立的内存空间,一个应用程序可以运行多个进程。

线程:线程是进程中的一个执行单元。

 

小结:

线程的作用是提供一个轻量级执行单元——虽比进程小,但仍能执行任何java代码。一般情况下,对操作系统来说,一个线程是一个完成的执行单元,但仍属于一个进程,进程的地址空间在组成该进程的所有线程之间共享。也就是说,每个线程都可以独立调度,而且有自己的栈和程序计数器,但会和同个进程中的其他线程共享内存和对象。

 

线程调度

  • 分时调度:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间
  • 抢占式调度:优先级高的线程使用CPU,如果线程的优先级相同,则随机选择一个(线程随机性),java的使用为抢占式调度

 

创建线程

创建多线程程序的第一种方式:

创建Thread类的子类
java.lang.Thread类:是描述线程的类,我们想要实现多线程程序,就必须继承Thread类

实现步骤:
1.创建一个Thread类的子类
2.在Thread类中的子类重写run方法
3.创建Thread类的子类对象
4.调用Thread类中的方法start,开启线程,执行run方法
(多次启动一个线程是非法的,特别是当线程已经结束后,不能再重新启动)
(java的线程使用为抢占式调度)

package demo1;

public class MyThread01 extends Thread{
	public void run() {
		for(int i=0;i<5;i++) {
			System.out.println("thread:"+i);
		}
	}
}
package demo1;

public class myDemo12 {
	public static void main(String[] args) throws Exception {
		MyThread01 myThread = new MyThread01();
		myThread.start();  //开辟新的栈空间,执行run方法
		
		for(int i=5;i<10;i++) {
			System.out.println("main:"+i);
		}
	}
}

运行结果:

main:5
thread:0
main:6
thread:1
main:7
thread:2
main:8
thread:3
main:9
thread:4

或者是:

使用匿名内部类

Thread thread = new Thread() {
			public void run() {
				for(int i=5;i<10;i++) {
					System.out.println("main:"+i);
				}
			}
		};
		
thread.start();

 

Thread常用方法

setName(Sting name);  //设置线程的名字

getName();  //获取线程的名字

sleep(long ms);   //暂定执行线程

join();     //让此线程强制执行,其他线程无法运行,必须等待此线程完成之后才可以继续执行

interrupt();    //当一个线程运行时,另外一个线程可以直接通过interrupt()方法中断其运行状态

setPriority(Thread.MIN_PRIORITY);  //设置线程的优先级为最低(NORM_PRIORITY中等,MAX_PRIORITY最高) 

【注意】并非优先级越高就一定会先执行,哪个线程先执行将由 CPU 的调度决定

yield();   //线程礼让,将一个线程的操作暂时让给其他线程执行

wait();   //线程等待,属于Object类,导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 唤醒方法

 

创建多线程程序的第二种方式:

实现Runnable接口

实现步骤:

1.创建一个Runnable接口的实现类
2.在实现类中重写Runnable接口的run方法
3.创建一个Runnable接口的实现类对象
4.创建Thread类对象,构造方法中传递Runnable接口的实现类对象
5.调用Thread类对象的start方法

package demo1;

public class ImpRunnable implements Runnable{
	@Override
	public void run() {
		for(int i=0;i<5;i++) {
			System.out.println("thread:"+i);
		}
	}

}
package demo1;

public class myDemo12 {
	public static void main(String[] args) throws Exception {
		ImpRunnable imp = new ImpRunnable();
		Thread run = new Thread(imp);
		run.start();
	}
}

或者使用匿名内部类

new Thread(new Runnable() {
			public void run() {
				for(int i=5;i<10;i++) {
					System.out.println("main:"+i);
				}
			}
		}).start();

或者用Lambda表达式替代匿名内部类

new Thread(()->{
	for(int i=5;i<10;i++){
	   System.out.println("main:"+i);
	}
  }).start();

使用Runnable接口的好处:
1.避免了单继承的局限性
2.增强程序的扩展性,降低了程序的耦合性(解耦)
(设置线程任务与开启线程进行隔离)

 

 

 

提示:

可以通过重载线程类的构造函数来传入参数,以便run方法使用

 

  • 同步与死锁

     参考:https://www.cnblogs.com/java1024/archive/2019/11/28/11950129.html  

一个多线程的程序如果是通过 Runnable 接口实现的,则意味着类中的属性被多个线程共享,那么这样就会造成一种问题,如果这多个线程要操作同一个资源时就有可能出现资源同步问题。

解决方法:

同步代码块

synchronized(同步对象){ 
  需要同步的代码 
}
class MyThread implements Runnable{ 
    private int ticket = 5 ;    // 假设一共有5张票 
    public void run(){ 
        for(int i=0;i<100;i++){ 
            synchronized(this){ // 要对当前对象进行同步 
                if(ticket>0){   // 还有票 
                    try{ 
                        Thread.sleep(300) ; // 加入延迟 
                    }catch(InterruptedException e){ 
                        e.printStackTrace() ; 
                    } 
                    System.out.println("卖票:ticket = " + ticket-- ); 
                } 
            } 
        } 
    } 
}; 
public class SyncDemo02{ 
    public static void main(String args[]){ 
        MyThread mt = new MyThread() ;  // 定义线程对象 
        Thread t1 = new Thread(mt) ;    // 定义Thread对象 
        Thread t2 = new Thread(mt) ;    // 定义Thread对象 
        Thread t3 = new Thread(mt) ;    // 定义Thread对象 
        t1.start() ; 
        t2.start() ; 
        t3.start() ; 
    } 
};

运行结果:

卖票:ticket = 5;
卖票:ticket = 4;
卖票:ticket = 3;
卖票:ticket = 2;
卖票:ticket = 1;

 

同步方法

除了可以将需要的代码设置成同步代码块外,也可以使用 synchronized 关键字将一个方法声明为同步方法。

 synchronized 方法返回值 方法名称(参数列表){ 
 
 }
class MyThread implements Runnable{ 
    private int ticket = 5 ;    // 假设一共有5张票 
    public void run(){ 
        for(int i=0;i<100;i++){ 
            this.sale() ;   // 调用同步方法 
        } 
    } 
    public synchronized void sale(){    // 声明同步方法 
        if(ticket>0){   // 还有票 
            try{ 
                Thread.sleep(300) ; // 加入延迟 
            }catch(InterruptedException e){ 
                e.printStackTrace() ; 
            } 
            System.out.println("卖票:ticket = " + ticket-- ); 
        } 

    } 
}; 
public class SyncDemo03{ 
    public static void main(String args[]){ 
        MyThread mt = new MyThread() ;  // 定义线程对象 
        Thread t1 = new Thread(mt) ;    // 定义Thread对象 
        Thread t2 = new Thread(mt) ;    // 定义Thread对象 
        Thread t3 = new Thread(mt) ;    // 定义Thread对象 
        t1.start() ; 
        t2.start() ; 
        t3.start() ; 
    } 
};

运行结果:

卖票:ticket = 5;
卖票:ticket = 4;
卖票:ticket = 3;
卖票:ticket = 2;
卖票:ticket = 1;

 

死锁

所谓死锁,就是两个线程都在等待对方先完成,造成程序的停滞,一般程序的死锁都是在程序运行时出现的。

 

 

参考:java技术手册

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章