java中有三种基本的使用方式:
继承Thread,重写run()方法 使用方式: public class ExtendThread extends Thread { @Override public void run() { for (int i = 0; i <50 ; i++) { System.out.println(this.getName()+" i="+i); } } } //运行 @org.junit.Test public void testDemo1(){ for (int i = 0; i <100 ; i++) { if(i==20){ new ExtendThread().start(); new ExtendThread().start(); new ExtendThread().start(); new ExtendThread().start(); } } } 运行结果: Thread-0 i=0 Thread-1 i=0 Thread-1 i=1 Thread-1 i=2 Thread-1 i=3 Thread-1 i=4 Thread-1 i=5 Thread-1 i=6 Thread-1 i=7 Thread-1 i=8 Thread-0 i=1 Thread-1 i=9 Thread-0 i=2 ... 实现Runable接口,重写run()方法: 使用方式: public class ImplRunable implements Runnable { @Override public void run() { for (int i = 0; i <100 ; i++) { System.out.println(Thread.currentThread().getName()+" i="+i); } } } //运行 @org.junit.Test public void testDemo1(){ for (int i = 0; i <100 ; i++) { if(i==20){ new ExtendThread().start(); new ExtendThread().start(); new ExtendThread().start(); new ExtendThread().start(); } } } 运行结果: “` Thread-1 i=0 Thread-1 i=1 Thread-1 i=2 Thread-1 i=3 Thread-1 i=4 Thread-1 i=5 Thread-1 i=6 Thread-1 i=7 Thread-1 i=8 Thread-1 i=9 Thread-1 i=10 Thread-1 i=11 Thread-1 i=12 Thread-0 i=0 Thread-0 i=1 … - 通过实现`Callable`接口,重写`call()`方法,最后用`Future`来包装成`Runable`: - 使用方式: ```java public class ImplCallable implements Callable<Integer> { @Override public Integer call() throws Exception { int i=0; for (; i<50 ; i++) { System.out.println(Thread.currentThread().getName()+" i="+i); } return i; } } //运行 @org.junit.Test public void testDemo3(){ for (int i = 0; i <100 ; i++) { if(i==20){ new Thread(new FutureTask(new ImplCallable())).start(); new Thread(new FutureTask(new ImplCallable())).start(); } } } <div class="se-preview-section-delimiter"></div> 运行结果: Thread-0 i=0 Thread-1 i=0 Thread-0 i=1 Thread-1 i=1 Thread-1 i=2 Thread-1 i=3 Thread-1 i=4 Thread-1 i=5 Thread-1 i=6 Thread-1 i=7 Thread-0 i=2 Thread-1 i=8 Thread-0 i=3 Thread-0 i=4 //... <div class="se-preview-section-delimiter"></div>java中线程总共有五种状态,分别是新建,就绪,运行,阻塞,死亡
新建:当程序中使用new关键字创建线程之后,该线程就处于新建状态,jvm仅仅为它分配内存以及初始化变量.就绪:当对线程对象调用start()后,线程进入就绪状态,注意这里该线程并不是立即运行,何时运行取决于jvm线程调度器调度.运行:jvm为处于就绪状态的线程分配到了cpu资源,线程体开始执行,但是该线程并不会一直运行,而是会有一定的运行时间,因为调度器需要给其他线程cpu资源.阻塞:比如对线程调用sleeep(),调用了阻塞IO等待该方法返回,请参照线程状态转换图.死亡:当线程执行体run(),call()执行完,运行意见出现错误/异常,主动调用stop(),都会使线程进入死亡状态.可以通过isAlive()返回判断线程的状态情况,当线程处于就绪,运行,阻塞时返回true,处于新建,死亡时返回false @org.junit.Test public void testDemo5() throws InterruptedException { for (int i = 0; i <10 ; i++) { System.out.println(Thread.currentThread().getName()+" i="+i); if(i==5){ Thread thread=new Thread(new ExtendThread());//新建状态 thread.start();//就绪状态 ,在之后一定时间内处于运行状态 thread.sleep(100);//阻塞状态,执行完run()方法会进入死亡状态 System.out.println(thread.isAlive()); } } } <div class="se-preview-section-delimiter"></div>上面的obj称为同步监视器,通常推荐将会被并发访问的资源作为同步监视器,整个流程可以概括为加锁->修改->释放锁. - 同步方法
public synchronized void setxxx(){ ... } <div class="se-preview-section-delimiter"></div>同步方法的监视器是this,this指的是调用该方法当前对象的引用 - 释放同步监视器的锁定 任何线程在进入同步代码块/同步方法之前都会获得对监视器对象的锁定,那么哪些情况下会释放对同步监视器的锁定呢?有以下几种情况: - 同步代码块/同步方法执行完毕 - 同步代码块/同步方法中遇到break,return终止程序的执行 - 同步代码块/同步方法执行过程中遇到遇到未处理的error或Exception - 执行监视器对象的wait()方法.
那么哪些情况对线程的操作不会释放锁呢? - 调用sleep(),yield()暂停当前线程,不会释放锁 - 调用suspend()挂起线程不会释放锁,但是应该尽量避免使用suspend()``resume()等方法
同步锁从jdk5开始java开始提供同步锁机制,锁由Lock来充当.
public class LockDemo { private final Lock lock = new ReentrantLock(); public void currentMethod() { lock.lock(); try { //发生并发的执行代码 } finally { lock.unlock(); } } }