标签:style blog http color os 使用 java io strong
1)继承java.lang.Thread类,重写run()方法。(run()方法是线程体)
2)定义实现java.lang.Runnable接口的类,实现run()方法。
可以使用一个线程类对象启动多个线程!多个线程对同一对象操作会相互影响。
基本状态图
包含线程同步的状态转换图
包含线程通信的状态转换图
1)位于对象等待池中:当线程调用了某个对象的wait()方法后,JVM会把线程放入这个对象的等待池中,直到该对象的notify或notifyAll方法在其他线程中被调用,才有可能唤醒本线程。
2)位于对象锁池中:当线程处于运行状态,试图获取某个对象的monitor(锁)时,若该对象锁已经被其他线程占用,则JVM将当前线程放入该对象的锁池中,直到该对象的锁被释放,当前线程才有可能获得该对象锁并解除阻塞状态。
3)其他阻塞状态:当前线程执行sleep方法或者调用其他线程的join方法时。发出I/O请求时也会发生阻塞。
线程同步:(协同步调)一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。
线程互斥:(共享资源访问排他性)当有若干个线程都要使用某一共享资源时,任何时刻最多只允许一个线程去使用,其它要使用该资源的线程必须等待,直到占用资源者释放该资源。线程互斥是线程同步到一种。
1)非静态synchronized方法
1 public class ThreadTest { 2 3 public static void main(String[] args) throws InterruptedException { 4 MyService sv = new MyService(); 5 ThreadDemo demo = new ThreadDemo(sv); 6 Thread th1 = new Thread(demo); 7 th1.start(); 8 9 Thread.sleep(500); //等待th1 进入运行状态 10 11 sv.init(); 12 th1.join(); 13 System.out.println("main thread finish"); 14 } 15 16 static class ThreadDemo implements Runnable { 17 private Object obj; 18 19 public ThreadDemo(Object obj) { 20 this.obj = obj; 21 } 22 23 public void run() { 24 try { 25 synchronized (obj) { 26 Thread.sleep(10000); 27 } 28 } catch (Exception e) { 29 } 30 } 31 } 32 33 static class MyService { 34 synchronized void init() { 35 System.out.println("MyService init"); 36 } 37 38 synchronized void service() { 39 System.out.println("MyService service"); 40 } 41 42 void testState() { 43 System.out.println("MyService state"); 44 } 45 } 46 }
运行结果是:mian线程等待10000毫秒后才调用sv.init()方法。因为th1里sv对象的monitor被一直持有10000毫秒。
结论:以synchronized修饰的非静态方法成为同步方法。线程需要获得该对象的monitor才能执行其同步方法。
2)静态synchronized方法
1 public class ThreadTest2 { 2 3 public static void main(String[] args) throws InterruptedException { 4 ThreadDemo demo = new ThreadDemo(); 5 Thread th1 = new Thread(demo); 6 th1.start(); 7 Thread.sleep(500); // 等待th1 进入运行状态 8 9 MyService.testState(); 10 System.out.println("main thread finish"); 11 } 12 13 static class ThreadDemo implements Runnable { 14 15 public void run() { 16 try { 17 MyService.testState(); 18 } catch (Exception e) { 19 } 20 } 21 } 22 23 static class MyService { 24 synchronized void init() throws InterruptedException { 25 System.out.println("MyService init"); 26 } 27 28 synchronized void service() { 29 System.out.println("MyService service"); 30 } 31 32 synchronized static void testState() throws InterruptedException { 33 System.out.println("MyService state"); 34 Thread.sleep(10000); 35 } 36 } 37 }
1 public class Test { 2 static Object lock = new Object(); 3 4 public static void main(String[] args) throws InterruptedException { 5 Thread th = new Thread(new MyThread_1()); 6 th.start(); 7 8 Thread th2 = new Thread(new MyThread_2()); 9 th2.start(); 10 11 th.join(); 12 th2.join(); 13 System.out.println("main thread finish"); 14 } 15 16 static class MyThread_1 implements Runnable { 17 18 public MyThread_1() { 19 } 20 21 public void run() { 22 System.out.println("MyThread 1 run"); 23 try { 24 Thread.sleep(1000); 25 synchronized (lock) { 26 System.out.println("MyThread 1 obtain lock, and sleep"); 27 Thread.sleep(10000); 28 System.out.println("MyThread 1 awake, and will release lock"); 29 } 30 } catch (Exception e) { 31 } 32 System.out.println("MyThread 1 finish"); 33 } 34 } 35 36 static class MyThread_2 implements Runnable { 37 public void run() { 38 System.out.println("MyThread 2 run"); 39 try { 40 synchronized (lock) { 41 System.out.println("MyThread 2 obtain lock"); 42 lock.wait(3000); 43 System.out.println("MyThread 2 re-obtain lock"); 44 } 45 } catch (Exception e) { 46 } 47 System.out.println("MyThread 2 finish"); 48 } 49 } 50 }
输出:
MyThread 1 run MyThread 2 run MyThread 2 obtain lock MyThread 1 obtain lock, and sleep MyThread 1 awake, and will release lock MyThread 1 finish MyThread 2 re-obtain lock MyThread 2 finish main thread finish
结论:当前线程执行lock.wait()必须拥有ock对象的monitor,而执行lock.wait()方法后,会释放monitor。lock.wait()执行完成后需要重新获取lock的monitor。
notify()/notifyAll()方法同样需要当前线程获得lock对象的monitor,会唤醒等待lock对象monitor的一个(所有)线程,但这(些)线程唤醒后必须重新获取lock的monitor。
当线程调用了start()方法后,isAlive()为true,直到线程死亡。
1)调整各个线程优先级
2)让线程执行sleep方法
3)让线程调用yield方法
4)让线程调用另一个线程的join方法。
setPriority(int)和getPriority()。如果想要保持可移植,应当设置:MAX_PRIORITY, MIN_PRIORITY, NORM_PRIORITY
当线程运行时,执行sleep方法,会放弃CPU,进入阻塞状态。
当线程在运行中执行了Thread类的yield()静态方法时,如果此时具有相同优先级的其它线程处于就绪状态,那么yield()方法将把当前运行的线程放到运行池中并使另一个线程运行。如果没有相同优先级的可运行线程,则yield()方法什么也不做。
二者都会使当前处于运行状态的线程放弃CPU,把运行机会让给别的线程。区别如下:
1)sleep不考虑线程优先级,可能把CPU让给优先级较低的线程。yield只让给优先级相同或更高的线程执行的机会。
2)执行sleep后,线程进入阻塞状态;执行yield后,线程进入就绪状态。
3)sleep方法抛出InterruptedException;yield方法不抛出任何异常。
4)sleep方法比yield方法有更好的移植性。
等待其它线程的结束。当前线程调用另外一个线程的join方法后,会转入阻塞状态,直到另一个线程运行结束才恢复到就绪状态。
原子操作:一个操作中的所有动作要么全做,要么全不做。原子操作是一个不可分割的基本单位,在执行过程中不允许被中断。
Java原子操作:
1.引用类型变量值的读和写。注意这儿是引用值的读写,而不是所引用对象内容的读和写。
2.除了long和double之外的简单类型的读和写。由于他们是64bit,JVM基本存储单元是32bit,无法在这一个时钟周期操作完成。
3.所有声明为volatile的变量的读和写,包括long和double类型以及引用类型对基本数据类型的赋值或者返回值操作。
自增操作(++)不是原子操作,因为涉及一次读和一次写。
临界区:任意时刻只允许一个线程访问的公共资源或者代码块。
同步代码块:以synchronized标记的代码块。能够保证多个线程按照正常逻辑访问临界区。
同步锁:每个JAVA对象都有且只有一个同步锁,在任何时刻,最多只允许一个线程拥有这把锁。
1) 如果同步代码块与非同步代码块同时操作共享资源,同样会造成资源争用。
2)每个对象都有唯一的同步锁。
3)静态方法可以加synchronized修饰符,同步锁为该方法所属类的类对象。所有该类的synchronized static方法的同步锁为类的类对象。
4)进入同步块执行的线程并非不间断执行,sleep、yield方法会使得线程将CPU让给其他线程,但不释放锁。而调用同步锁对象的wait方法后同样会让出CPU,且会释放锁。
5)synchronized方法不被继承。子类若覆盖父类的synchronized 方法,则该方法不再是synchronized方法,除非声明为synchronized。
1)该类的对象可以被多个线程安全访问。
2)每个线程能够正常执行原子操作,并得到正确结果。
3)每个线程的原子操作执行完成后,对象处于合理状态。
1)线程执行完毕同步代码块(方法)。
2)线程在执行同步代码块过程遇到异常。
3)线程在执行同步代码块过程,调用锁所属对象的wait()方法,会释放锁,线程进入锁所属对象的等待池。
当一个线程A等待线程B持有的锁,而同时线程B等待线程A持有的锁(或者线程B间接等待线程A的锁),就发生了死锁。
1 public class DeathLock { 2 public static void main(String[] args) throws InterruptedException { 3 Object o1 = new Object(); 4 Object o2 = new Object(); 5 Thread th = new Thread(new MyThread(o1, o2)); 6 Thread th2 = new Thread(new MyThread(o2, o1)); 7 8 th.start(); 9 th2.start(); 10 } 11 12 static class MyThread implements Runnable { 13 14 private Object lock; 15 private Object target; 16 17 public MyThread(Object lock, Object target) { 18 this.lock = lock; 19 this.target = target; 20 } 21 22 @Override 23 public void run() { 24 try { 25 synchronized (lock) { 26 Thread.sleep(1000); 27 System.out.println(String.format("hold %s, wait for %s ", 28 lock, target)); 29 synchronized (target) { 30 } 31 } 32 } catch (InterruptedException e) { 33 e.printStackTrace(); 34 } 35 } 36 } 37 38 }
基本原则:让所有线程按照同样顺序获得一组锁。
方法:1)将多锁组成一个组放到一个锁下。
2)标记各个锁对象锁的状态是否已被占用。这样当线程试图获取该某个对象的锁,而且锁已经被占用时,可以延迟进行再次尝试,避免死锁产生。
根本:仔细考虑涉及多线程的整个系统,对关键资源、模块进行深入分析。
Java.lang.Object类中提供了两个用于线程通信的方法:
1)wait()方法。线程执行某个对象的wait方法后将释放该对象的锁,并进入到该对象的等待池中。等待其他线程将本线程唤醒。
2)notify/notifyAll方法。执行某个对象的这两个方法后,JVM从该对象的等待池中随机选择一个(全部选择)线程,并将它(们)放入该对象的锁池中。
标签:style blog http color os 使用 java io strong
原文地址:http://www.cnblogs.com/xzzzzzzzz/p/3276732.html