1、线程API知识点java
1.sleep()方法缓存
做用是在指定的毫秒数内让当前“正在执行的线程”休眠(暂停执行),这个正在执行的线程是指this.currentThread()返回的线程。安全
代码:多线程
Thread.sleep(2000)
2.getId()方法并发
做用是取得线程的惟一标识。ide
3.中止线程函数
a.使用Thread.stop()方法,可是这个方法是废弃的。性能
b.使用Thread.interrupt()方法,但这个方法不会终止一个正在运行的线程,还须要加入一个判断才能够完成线程的终止。测试
c.异常也能够中止线程。this
三种方法:
1)、使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。
2)、使用stop方法强行终止线程,可是不推荐使用这个方法,由于stop和suspend及resume同样,都是做废过时的方法,使用它们可能产生不可预料的结果。
3)、使用interrupt方法中断线程。
--------------------------------------------------------------------------------------------------
使用interrupt方法的效果并不像for+break语句那样,立刻就中止,调用interrupt方法只是在当前线程打了一个中止的标记,并非真的中止线程。代码:
Thread thread = new Thread(); thread.start(); thread.interrupt();//打下标记
判断线程是不是中止的状态
a.this.interruptted():测试当前线程是否已经中断,执行以后具备将状态标志清除为false的功能。
b.this.isInterrupted():测试线程是否已经中断,但不清除状态。
4.yield方法
做用是放弃当前的cpu资源,将它让给其余的任务去占用CPU执行时间。但放弃的时间不肯定,有可能刚刚放弃,立刻又得到CPU时间片。
Thread.yield()
5.线程的优先级
设置线程的优先级使用setPriority()方法。线程的优先级分为1~10个等级,若是小于1或大于10,则JDK抛出异常throw new IllegalArgumentException().
Thread.currentThread().setPriority(6);
注意:线程的优先级具备随机性。
6.守护线程
典型的守护线程就是垃圾回收线程,当进程中没有守护线程了,则垃圾回收线程也就没有存在的必要了,自动销毁。守护即线程的做用是为其余线程的运行提供便利服务,最典型的应用就是GC。
Thread thread = new Thread(); thread.setDaemon(true);//设置为守护线程
2、对象及变量的并发访问(synchronized)
1.synchronized同步方法
a.方法加synchronized
private int num; synchronized public void add(String name){ try{ if(name.equals("b")){ num =100; System.out.println(num); }else{ num = 200; System.out.println(num); } }catch(InterruptedException e){ e.printStackTrace(); } }
关键字synchronized取得的所都是对象锁,而不是一段代码或方法(函数)看成锁,因此那个线程先执行带synchronized关键字的方法,那个线程就持有该方法所属对象的锁Lock,其余线程只能呈等待状态,可是前提是多个线程访问的是同一个对象。
注意:set和get方法,若是set方法上有synchronized修饰,则get方法上也应该加上,否则就出现数据不一致。
2.synchronized锁重入
概念是:本身能够再次获取本身的内部锁。好比有1条线程得到了某个对象的锁,此时这个对象锁尚未释放,当其次想要获取这个对象的锁的时候仍是能够获取的,若是不可锁重入的话,就会形成死锁。
synchronized public void service1(){ System.out.println("service1"); service2(); } synchronized public void service2(){ System.out.println("service2"); }
同时,当存在父子类继承关系时。子类彻底能够经过“可重入锁”调用父类的同步方法,可是锁不具备继承性。假如线程出现了异常,锁自动释放。
3.synchronized同步代码块
public void service3(){ synchronized (this) { System.out.println("service3"); } }
在使用同步synchronized(this)代码块时须要注意的是,当一个线程访问object的一个synchronized(this)同步代码块时,其余线程对同一个object中全部其余synchronized(this)同步代码块的访问将被阻塞,这说明synchronized使用的是“对象监视器”。同时代码块也是锁定当前对象的。
多个线程调用同一个对象中的不一样名称的synchronized同步方法或synchronized(this)同步代码块时,调用的效果就是按顺序执行,也就是同步的,阻塞的。
(1)、synchronized同步方法
a.对其余synchronized同步方法或synchronized(this)同步代码块调用呈阻塞状态。
b.同一时间只有一个线程能够执行synchronized同步方法中的代码。
同理synchronized代码块也是同样的。
(2)、同步代码块
支持任意对象做为对象监视器来实现同步的功能。这个“任意对象”大多数是实例变量及方法的参数,使用格式为synchronized(非this对象)。
a.在多线程持有“对象监视器”为同一个对象的前提下,同一时间只有一个线程能够执行synchronized(非对象x)同步代码块中的代码。
b.当持有“对象监视器”为同一个对象的前提下,同一时间只有一个线程能够执行synchronized(非this对象X)同步代码中的代码。
//同步代码对象 class Service{ private String anyString = new String();//若是这个放进setString方法里面就会出现数据的不一致。 public void setString(String userName){ synchronized (anyString) { System.out.println("业务处理"); try { Thread.sleep(20000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } class ThreadA extends Thread{ private Service service ; public ThreadA(Service service) { super(); this.service = service; } public void run(){ System.out.println("业务处理A"); service.setString("a"); } } class ThreadB extends Thread{ private Service service ; public ThreadB(Service service) { super(); this.service = service; } public void run(){ System.out.println("业务处理B"); service.setString("B"); } } public static void main(String[] args) { Service service = new Service(); ThreadA threadA = new ThreadA(service); threadA.setName("a"); threadA.start(); ThreadB threadB = new ThreadB(service); threadB.setName("B"); threadB.start(); }
总结:synchronized(非this对象X)格式的写法是将X对象自己做为对象监视器,如下是结论。
a.当多个线程同时执行synchronized(X){}同步代码块时呈同步效果。
b.当其余线程执行X对象中synchronized同步时呈同步效果。
c.当其余线程执行X对象方法时里面的synchronized(this)代码块时也呈现同步效果。
静态同步synchronized和同步synchronized 的区别:synchronized关键字加到static静态方法上是给Class类上锁,而synchronized关键字加到非static静态方法上是给对象加锁。
注意:
将synchronized(String) 同步块与String联合使用时,须要注意的是由于JVM会为String进行缓存,因此会出现线程不能执行的问题。因此同步synchronized代码块时都不使用String做为锁对象,而改用其余,好比new Object()实例一个Object对象,它不会放入缓存。
总结:
关键字synchronized能够保证在同一时刻,只有一个线程能够执行某一个方法或一个代码块。它包含两个特征:互斥性和可见性。同步synchronized不只能够解决一个线程看到对象处于不一致的状态,还能够保证进入同步方法或者同步代码块的每一个线程,都看到由同一个锁保护以前的修改为果。
4.死锁
4.1 同步synchronized方法无线等待与解决
死锁举例代码一:
synchronized public void service1(){ System.out.println("service1"); boolean isCount = true; while(isCount){ } System.out.println("service1 end"); }
死锁举例代码二:
public class test2 implements Runnable{ public Object lock1 = new Object(); public Object lock2 = new Object(); public String uname; public void setUname(String uname) { this.uname = uname; } @Override public void run() { if(uname.equals("a")){ synchronized (lock1) { try { System.out.println(uname); Thread.sleep(20000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } synchronized (lock2) { System.out.println("lock2"); } } } if(uname.equals("b")){ synchronized (lock2) { try { System.out.println(uname); Thread.sleep(20000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } synchronized (lock1) { System.out.println("lock1"); } } } } }
总结:1.while循环加上推荐语句,容易出现。
2.双方互相有对方的锁的状况。
3、对象及变量的并发访问(volatile)
1.volatile相关的概念和做用
关键字volatile的主要做用是使变量在多个线程间可见。
解决上面死锁的问题。
class test extends Thread{ volatile private boolean isRuning = true; public boolean isRuning(){ return isRuning; } public void run(){ while(isRuning == true){ } } }
关键字volatile的做用是强制从公共堆栈中取得变量的值,而不是从线程私有数据栈中取得变量的值。
使用volatile关键字增长了实例变量在多个线程之间的可见性。但volatile关键字最致命的缺点是不支持原子性。
注意:改变实例变量中的数据,好比i++,并非原子操做,也就不是线程安全的,详细步骤分解为:
a.从内存中取出i的值;b.计算i的值;c.将i的值写到内存中。步骤b容易出息问题。
总结:对于volatile修饰的变量,JVM虚拟机只是保证从内存加载到线程工做内存的值是最新的,也就是说,volatile关键字解决的是变量读时的可见性问题,但没法保证原子性,对于多个线程访问同一个实例变量仍是须要同步加锁。
对于上面的i++,JDK 提供了AtomicInteger原子类进行实现。相关的API在util包下面。
2.volatile和synchronized的对比
a.关键字volatile是线程同步的轻量级实现,因此volatile性能比synchronized要好,而且volatile只能修饰变量,而synchronized能够修饰方法,以及代码块。
b.多线程访问volatile不会发生阻塞,而synchronized会出现阻塞。
c.volatile能保证数据的可见性,但不能保证原子性;而synchronized能够保证原子性,也能够间接保证可见性,由于它会将私有内存和公共内存中的数据作同步。