【线程】线程基础

参考别人的文章以及自己的理解将java多线程的相关知识进行总结。

1、线程的生命周期

在这里插入图片描述
上图展示的是一个线程的生命周期,【图片来源于网络】,完整的生命周期分为以下几步:
(1)、新建状态
使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。
(2)、就绪状态
当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。
(3)、运行状态
如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。

在运行状态下如果线程主动调用 yield() 方法,则会由运行状态转换到就绪状态

(4)、阻塞状态
如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:

  • 等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。
  • 同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。
  • 其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。

(5)、死亡状态
一个运行状态的线程完成任务或者其他终止条件(调用stop()或者destory()函数)发生时,该线程就切换到终止状态。

注意:
1、wait()方法是属于对象的,一般应用于线程同步时,如果执行了wait()方法,当前线程会让出CPU和对象锁,当前线程进入到等待池中,可以由其他线程使用notifyAll()(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程)来进行唤醒从而进入到锁池中,如果获取到锁则可以继续向下执行。
2、sleep()方法:如果线程进入sleep的话,释放cpu资源,如果外层包有Synchronize,那么此锁并没有释放掉。
3、wait用于锁机制,sleep不是,这就是为啥sleep不释放锁,wait释放锁的原因,sleep是线程的方法,跟锁没半毛钱关系,wait,notify,notifyall 都是Object对象的方法,是一起使用的,用于锁机制,需要搭配synchonized关键字使用。
4、join()方法:一种特殊的wait,当前运行线程调用另一个线程的join方法,当前线程进入阻塞状态直到另一个线程运行结束等待该线程终止。 注意该方法也需要捕捉异常。

example:

public class WaitAndNotify {
public static void main(String[] args) {
        Object co = new Object();
        System.out.println(co);
 
        for (int i = 0; i < 5; i++) {
            MyThread t = new MyThread("Thread" + i, co);
            t.start();
        }
 
	try {
            TimeUnit.SECONDS.sleep(2);
            System.out.println("-----Main Thread notify-----");
            synchronized (co) {
                co.notify();
            }
 
            TimeUnit.SECONDS.sleep(2);
            System.out.println("Main Thread is end.");
 
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
 
static class MyThread extends Thread {
private String name;
        private Object co; 
        public MyThread(String name, Object o) {
			this.name = name;
            this.co = o;
        }
 
		@Override
        public void run() {
            System.out.println(name + " is waiting.");
            try {
					synchronized (co) {
						co.wait();
               		 }
               		 System.out.println(name + " has been notified.");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
 
 
运行结果:
java.lang.Object@1540e19d
Thread1 is waiting.
Thread2 is waiting.
Thread0 is waiting.
Thread3 is waiting.
Thread4 is waiting.
-----Main Thread notify-----
Thread1 has been notified.
Main Thread is end.
 
将其中的那个notify换成notifyAll,运行结果:
Thread0 is waiting.
Thread1 is waiting.
Thread2 is waiting.
Thread3 is waiting.
Thread4 is waiting.
-----Main Thread notifyAll-----
Thread4 has been notified.
Thread2 has been notified.
Thread1 has been notified.
Thread3 has been notified.
Thread0 has been notified.
Main Thread is end.

2、创建线程

2.1 实现 Runnable 接口来创建线程
public class ImplementRunnable implements Runnable {

	@Override
	public void run() {
		
	}
}
2.2 继承Thread来创建线程
public class ExtendsThread extends Thread {

	@Override
	public void run() {
		// TODO Auto-generated method stub
		super.run();
	}

}
2.3 使用Callable和Future接口创建线程

具体是创建Callable接口的实现类,并实现call()方法。并使用FutureTask类来包装Callable实现类的对象,且以此FutureTask对象作为Thread对象的target来创建线程。

public class ThreadTest {
    public static void main(String[] args) {
        Callable<Integer> myCallable = new MyCallable();    // 创建MyCallable对象
        FutureTask<Integer> ft = new FutureTask<Integer>(myCallable); //使用FutureTask来包装MyCallable对象

        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
            if (i == 30) {
                Thread thread = new Thread(ft);   //FutureTask对象作为Thread对象的target创建新的线程
                thread.start();                      //线程进入到就绪状态
            }
        }

        System.out.println("主线程for循环执行完毕..");
        
        try {
            int sum = ft.get();            //取得新创建的新线程中的call()方法返回的结果
            System.out.println("sum = " + sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}


class MyCallable implements Callable<Integer> {
    private int i = 0;
    // 与run()方法不同的是,call()方法具有返回值
    @Override
    public Integer call() {
        int sum = 0;
        for (; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
            sum += i;
        }
        return sum;
    }
}

参考内容一:Java 多线程编程
参考内容二:java中的notify和notifyAll有什么区别?

发布了66 篇原创文章 · 获赞 6 · 访问量 9424

猜你喜欢

转载自blog.csdn.net/qgnczmnmn/article/details/102721887