1.线程生命周期
(1) 新建
(2) 就绪
(3) 运行
(4) 阻塞:1.正常切换 2.sleep()方法 3.wait()方法 4.执行某个操作进入阻塞状态(等待IO、等待某个通知、试图获得一个同步监视器等)
(5) 死亡
2.创建线程的方法
(1)继承Thread类
(2)实现Runnable接口
(3)使用Callable和Future创建线程
import java.util.concurrent.Callable;import java.util.concurrent.FutureTask;public class Main implements Callable{ public static void main(String[] args) { Main main = new Main(); FutureTask task = new FutureTask (main); new Thread(task, "子线程").start(); try { System.out.println("子线程返回值:"+ task.get()); } catch(Exception e) { e.printStackTrace(); } } public Integer call() throws Exception { int i = 0; for(; i < 100; i++) { System.out.println(Thread.currentThread().getName()+"的变量i的值:"+i); } return i; }}
比较:Runnable与Callable方式基本相同,只是Callable接口里定义的方法有返回值,可以声明抛出异常而已。
所以暂时将两者归为同一种方式。这种方式与继承Thread类的主要区别为:
(1)线程实现了Runnable接口,还可以继承其他类
(2)多个线程可以共享同一个target对象,多个线程共享该对象的成员变量
3.目标对象与线程的关系(后续上代码解释)
(1)目标对象与线程完全解耦
(2)目标线程组合线程(弱耦合)
4.线程优先级与调度管理
(1)Java线程的优先级都在常数1~10的范围内,默认为5。
(2)setPriority(int)和getPriority()。
(3)Java调度器的任务是使高优先级的线程能始终运行,一旦时间片有空闲,则使具有同等优先级的线程以轮流的方式顺序使用时间片。在实际编程中,不提倡使用线程的优先级来保证算法的正确执行。
5.线程控制方法
(1)sleep(int millsecond):单位毫秒
(2)yield():与sleep()方法相似,称为线程让步,使线程暂停,但不会阻塞线程,只是将线程转入就绪状态,让系统的调度器重新调度一次。
与sleep()区别:sleep()方法暂停当前线程,会给其他线程机会,不理会其他线程的优先级;但yield()方法只会给有优先级相同或更高的线程执行机会。
sleep()方法将线程转入阻塞状态;而yield()方法将线程转入就绪状态
(3)isAlive():检查线程是否处于运行状态的方法
注意:一个已经运行的线程在没有进入死亡状态时,不要再给线程分配线程实体,由于线程只能引用最后分配的实体,先前的实体就会变成“垃圾”,并且不会被垃圾收集器收集。
(4)interrupt()
(5)join():称为线程联合
一个线程A在占用CPU资源期间,可以让其他线程调用join()和本线程联合,如B.join();
我们称A在运行期间联合了B,如果线程A在占用CPU资源期间一旦联合线程B,那么A线程将立刻中断执行,一直等到它联合的线程B执行完毕,线程A再重新排队等待CPU资源,以便恢复执行。如果A准备联合的B已经结束,那么B.join()不会产生任何效果。
(6)setDaemon(boolean on):称为后台线程或守护线程
一个线程调用void setDaemon(boolean on)方法可以将自己设置成一个守护线程。当程序中所有用户线程已结束运行,即使守护线程的run()方法中还有需要执行的语句,守护线程也立刻结束执行。
6.线程同步方法
(1)synchronized关键字:
synchronized(obj)
{
//同步代码块
}
其中obj称为同步监视器
(2)同步锁(Lock)(后续上代码)
7.线程通信方法
(1)wait()、notify()、notifyAll():适用于用synchronized修饰的方法或代码块
import java.util.Scanner;public class Main{ public static void main(String[] args) { A a = new A(); B b = new B(); Thread aThread = new Thread(a); Thread bThread = new Thread(b); aThread.start(); bThread.start(); while(true) { Scanner reader = new Scanner(System.in); int type = reader.nextInt(); if(type == 1) a.restart(); else if(type == 2) b.restart(); } } } class A implements Runnable { int number = 0; public void run() { while(true) { number++; System.out.println(Thread.currentThread().getName()+":number="+number); if(number%5 == 0) { System.out.println(Thread.currentThread().getName()+"挂起"); try { hangUp(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"恢复执行"); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } public synchronized void hangUp() throws InterruptedException { wait(); } public synchronized void restart() { notifyAll(); } } class B implements Runnable { int number = 0; public void run() { while(true) { number--; System.out.println(Thread.currentThread().getName()+":number="+number); if(number%10 == 0) { System.out.println(Thread.currentThread().getName()+"挂起"); try { hangUp(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"恢复执行"); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } public synchronized void hangUp() throws InterruptedException { wait(); } public synchronized void restart() { notifyAll(); }}//控制台输入1唤醒子线程aThread,2唤醒子线程bThread
(2)Conditon:程序使用Lock来同步,系统中存在隐式的同步监视器,也就不能用wait()、notify()方法,此时可使用Condition方法:await()、signal()、signalAll()。
(3)阻塞队列(BLockingQueue):特别适合于生产者消费者问题
8.线程池:(后续上代码)
(1)Excutors:
(2)ForkJoinPool:特别适用于多CPU做并行处理
9.线程相关类
(1)ThreadLocal:代表一个线程局部变量,让每一个线程创建该变量的副本,从而避免并发访问的线程安全问题
(2)使用Collections提供的静态方法把集合包装成线程安全的集合,例如:
HashMap h = Collections.synchronizedMap(new HashMap());
(3)ConcurrentHashMap、CopyOnWriteArrayList等