一、什么是线程
个人理解:线程就是轻量的进程,产生在进程里面,一个进程可以有多个线程。
二、线程的基本操作
1、新建状态(new): 当用new操作符创建一个线程时, 例如new Thread(r),线程还没有开始运行,此时线程处在新建状态。 当一个线程处于新生状态时,程序还没有开始运行线程中的代码。
Thread thread = new Thread();
2、就绪状态(Runnable):一个新创建的线程并不自动开始运行,要执行线程,必须调用线程的start()方法。当线程对象调用start()方法即启动了线程,start()方法创建线程运行的系统资源,并调度线程运行run()方法。当start()方法返回后,线程就处于就绪状态。
Thread thread = new Thread() { @Override public void run() { try { System.out.println("thread 3 running...."); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { System.out.println("thread 3 stoped...."); } } };
3、运行状态(Running): 当线程获得CPU时间后,它才进入运行状态,真正开始执行run()方法。注意:调用run()方法并不是启动一个线程,只是调用了一个方法
Thread thread = new Thread(); thread.start();
4、阻塞状态(Blocked):所谓阻塞状态是正在运行的线程没有运行结束,暂时让出CPU,这时其他处于就绪状态的线程就可以获得CPU时间,进入运行状态。
thread.sleep(); thread.wait();
上面两种方法都能让线程处于阻塞状态,区别在于sleep()不会释放锁,wait()会释放锁;sleep是Thread方法,wait()是Object方法
5、死亡状态(Dead):正常执行完run方法和执行run方法异常都会使线程死亡;为了确定线程在当前是否存活着(就是要么是可运行的,要么是被阻塞了),需要使用isAlive方法。如果是可运行或被阻塞,这个方法返回true; 如果线程仍旧是new状态且不是可运行的, 或者线程死亡了,则返回false
6、终止线程
Thread.stop();//不推荐使用。它会释放所有monitor 会出现消息不一致情况
7、中断线程
public void Thread.interrupt() // 中断线程 public boolean Thread.isInterrupted() // 判断是否被中断 public static boolean Thread.interrupted() // 判断是否被中断,并清除当前中断状态
8、挂起(suspend)和继续执行(resume)线程
– suspend()不会释放锁
– 如果加锁发生在resume()之前 ,则死锁发生
9、等待线程结束(join)和谦让(yeild)
join()方法
package com.cc.thread; import org.junit.Test; public class ThreadTest01 { /** * 现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行? * Java Thread中, join() 方法是让调用该方法的主线程执行run()时暂时卡住,等run()执行完成后, 主线程再调用执行join()后面的代码 * 如果去掉t1.join()这个语句过后, 输出的顺序是乱的, 加上这个语句后, 就会按照顺序输出, 从某种意义上说实现了同步。 */ @Test public void Test1(){ //线程1 Thread thread1 = new Thread() { @Override public void run() { try { System.out.println("thread 1 running...."); //sleep(1000); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { System.out.println("thread 1 stoped...."); } super.run(); } }; //线程2 Thread thread2 = new Thread() { @Override public void run() { try { System.out.println("thread 2 running...."); //sleep(1000); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { System.out.println("thread 2 stoped...."); } super.run(); } }; //线程3 Thread thread3 = new Thread() { @Override public void run() { try { System.out.println("thread 3 running...."); //sleep(1000); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { System.out.println("thread 3 stoped...."); } super.run(); } }; try { thread1.start(); thread1.join(); thread2.start(); thread2.join(); thread3.start(); thread3.join(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
yield()方法
package com.cc.demo01; /** * yield()谦让 * 使当前线程从执行状态(运行状态)变为可执行态(就绪状态)。cpu会从众多的可执行态里选择,也就是说, * 当前也就是刚刚的那个线程还是有可能会被再次执行到的,并不是说一定会执行其他线程而该线程在下一次中不会执行到了。 * @author chao * */ public class ThreadDemo02 extends Thread { public ThreadDemo02(String name) { super(name); } public void run() { for (int i = 1; i <= 30; i++) { System.out.println("" + this.getName() + "-----" + i); // 当i为10时,该线程就会把CPU时间让掉,让其他或者自己的线程执行(也就是谁先抢到谁执行) if (i == 10) { this.yield(); } } } public static void main(String[] args) { ThreadDemo02 t1 = new ThreadDemo02("张三"); ThreadDemo02 t2 = new ThreadDemo02("李四"); t1.start(); t2.start(); } }
10、守护线程
在后台默默地完成一些系统性的服务,比如垃圾回收线程、 JIT线程就可以理解为守护线程
当一个Java应用内,只有守护线程时,Java虚拟机就会自然退出
Thread t=new DaemonT();
t.setDaemon(true);
t.start();
11、线程优先级
public final static int MIN_PRIORITY = 1;
public final static int NORM_PRIORITY = 5;
public final static int MAX_PRIORITY = 10;
package com.cc.demo01; /** * yield()谦让 * 使当前线程从执行状态(运行状态)变为可执行态(就绪状态)。cpu会从众多的可执行态里选择,也就是说, * 当前也就是刚刚的那个线程还是有可能会被再次执行到的,并不是说一定会执行其他线程而该线程在下一次中不会执行到了。 * @author chao * */ public class ThreadDemo02 extends Thread { public ThreadDemo02(String name) { super(name); } public void run() { for (int i = 1; i <= 30; i++) { System.out.println("" + this.getName() + "-----" + i); // 当i为10时,该线程就会把CPU时间让掉,让其他或者自己的线程执行(也就是谁先抢到谁执行) if (i == 10) { this.yield(); } } } public static void main(String[] args) { ThreadDemo02 t1 = new ThreadDemo02("张三"); ThreadDemo02 t2 = new ThreadDemo02("李四"); t1.start(); //优先级高的会在下次竞争中更容易获胜 t1.setPriority(MIN_PRIORITY); t2.start(); t2.setPriority(MAX_PRIORITY); } }
三、基本的线程同步操作
synchronized
– 指定加锁对象:对给定对象加锁,进入同步代码前要获得给定对象的锁。
– 直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。
– 直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁。
Object.wait() Obejct.notify();
package com.cc.thread; public class ThreadTest02{ public static final Object obj = new Object(); public static void main(String[] args) { new Thread(new Producer()).start(); new Thread(new Consumer()).start(); } } /** * 两个线程依次打印"A""B",总共打印10次。 * * @author chao 这里使用static * obj作为锁的对象,当线程Produce启动时(假如Produce首先获得锁,则Consumer会等待),打印 * “A”后,会先主动释放锁,然后阻塞自己 * 。Consumer获得对象锁,打印“B”,然后释放锁,阻塞自己,那么Produce又会获得锁,然后...一直循环下去,直到count = * 0.这样,使用Synchronized和wait()以及notify()就可以达到线程同步的目的。 * */ class Consumer implements Runnable{ @Override public void run() { int count = 10; while(count>0){ synchronized (ThreadTest02.obj) { //wait()和notify()必须在synchronized代码块中调用 System.out.println("B"); count --; ThreadTest02.obj.notify(); // 主动释放对象锁 try { ThreadTest02.obj.wait();//阻塞当前对象 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } class Producer implements Runnable{ @Override public void run() { int count = 10; while(count>0){ synchronized (ThreadTest02.obj) { System. out.println( "A"); count --; ThreadTest02.obj.notify();//主动释放当前对象锁 try { ThreadTest02.obj.wait();//阻塞当前对象 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }