获取对象锁的两种方法:一是同步代码块(synchronized(this),sybchronized(类实例对象)),锁是小括号()中的实例对象;二是同步非静态方法(synchronized method),锁是当前对象的实例对象。
package com.javabasic.bytecode.thread;
import java.text.SimpleDateFormat;
import java.util.Date;
public class SyncThread implements Runnable {
@Override
public void run() {
String threadName = Thread.currentThread().getName();
if (threadName.startsWith("A")){
async();
} else if (threadName.startsWith("B")){
syncObjectBlock1();
} else if (threadName.startsWith("C")){
syncObjectMethod1();
}
}
/*synchronized修饰非静态方法*/
private synchronized void syncObjectMethod1() {
System.out.println(Thread.currentThread().getName() + "_SyncObjectMethod1:" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
try {
System.out.println(Thread.currentThread().getName() + "_SyncObjectMethod1_Start:" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + "_SyncObjectMethod1_End:" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
} catch (InterruptedException e){
e.printStackTrace();
}
}
/*方法中有synchronized(this|objrct){}同步代码块*/
private void syncObjectBlock1() {
System.out.println(Thread.currentThread().getName() + "_SyncObjectBlock1:" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
synchronized (this){
try {
System.out.println(Thread.currentThread().getName() + "_SyncObjectBlock1_Start:" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + "_SyncObjectBlock1_End:" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
} catch (InterruptedException e){
e.printStackTrace();
}
}
}
/*异步方法*/
private void async() {
try {
System.out.println(Thread.currentThread().getName() + "_Async_Start:" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + "_Async_End:" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
} catch (InterruptedException e){
e.printStackTrace();
}
}
public static void main(String[] args) {
SyncThread syncThread = new SyncThread();
Thread A_thread1 = new Thread(syncThread,"A_thread1");
Thread A_thread2 = new Thread(syncThread,"A_thread2");
Thread B_thread1 = new Thread(syncThread,"B_thread1");
Thread B_thread2 = new Thread(syncThread,"B_thread2");
Thread C_thread1 = new Thread(syncThread,"C_thread1");
Thread C_thread2 = new Thread(syncThread,"C_thread2");
A_thread1.start();
A_thread2.start();
B_thread1.start();
B_thread2.start();
C_thread1.start();;
C_thread2.start();
}
}
获取类锁的两种方法:一是同步代码块(synchronized(类.class)),锁是小括号()中的类对象(Class对象);二是同步静态方法(synchronized static method),锁是当前对象的类对象(Class对象)。
package com.javabasic.bytecode.thread;
import java.text.SimpleDateFormat;
import java.util.Date;
public class SyncThread implements Runnable {
@Override
public void run() {
String threadName = Thread.currentThread().getName();
if (threadName.startsWith("A")){
async();
} else if (threadName.startsWith("D")){
syncClassBlock1();
} else if (threadName.startsWith("E")){
syncClassMethod1();
}
}
/*异步方法*/
private void async() {
try {
System.out.println(Thread.currentThread().getName() + "_Async_Start:" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + "_Async_End:" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
} catch (InterruptedException e){
e.printStackTrace();
}
}
private void syncClassBlock1() {
System.out.println(Thread.currentThread().getName() + "_SyncClassBlock1:" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
synchronized (SyncThread.class){
try {
System.out.println(Thread.currentThread().getName() + "_SyncClassBlock1_Start:" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + "_SyncClassBlock1_End:" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
} catch (InterruptedException e){
e.printStackTrace();
}
}
}
private synchronized static void syncClassMethod1() {
System.out.println(Thread.currentThread().getName() + "_SyncClassMethod1:" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
try {
System.out.println(Thread.currentThread().getName() + "_SyncClassMethod1_Start:" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + "_SyncClassMethod1_End:" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
} catch (InterruptedException e){
e.printStackTrace();
}
}
public static void main(String[] args) {
Thread A_thread1 = new Thread(new SyncThread(),"A_thread1");
Thread A_thread2 = new Thread(new SyncThread(),"A_thread2");
Thread D_thread1 = new Thread(new SyncThread(),"D_thread1");
Thread D_thread2 = new Thread(new SyncThread(),"D_thread2");
Thread E_thread1 = new Thread(new SyncThread(),"E_thread1");
Thread E_thread2 = new Thread(new SyncThread(),"E_thread2");
A_thread1.start();
A_thread2.start();
D_thread1.start();
D_thread2.start();
E_thread1.start();
E_thread2.start();
}
}
对象锁和类锁的总结:使用对象锁时,多个线程访问同一个对象,会产生竞争关系,但是多个线程访问同一个类实例化的不同对象,则不会发生竞争关系,即多个线程之间互不干扰;使用类锁时,多个线程访问同一对象或者是同一类实例化的不同对象时,都会发生竞争关系;同一个类中的类锁和对象锁不会相互干扰,不会有竞争关系。
自旋锁:
自适应自旋锁:
锁消除是JVM更彻底的优化,JIT编译时,对上下文进行扫描,去除不可能存在竞争的锁;锁粗化时另一种极端,通过加锁的范围,避免反复加锁和解锁
无锁、偏向锁、轻量级锁、重量级锁
偏向锁:较少同一线程获取锁的代价。大多数情况下,所不存在多线程竞争关系,总是由同一线程多次获得。
轻量级锁:是由偏向锁升级来的,偏向锁运行在一个线程进入同步块的情况下,当第二个线程加入锁争用的时候,偏向锁就会升级为轻量级锁。适用于线程交替执行的同步块。若存在同一时间两个线程访问同一锁的情况,就会导致轻量级锁升级为重量级锁
ReentrantLock(再入锁):能够实现比synchronized更细粒度的控制,如控制fairness(锁的公平);调用lock()之后,必须调用unlock()来释放锁;性能未必比synchronized高,并且也是可重入的。
ReentrantLock公平性的设置 :ReentrantLock fairLock = new ReentrantLock(true);参数为true时,倾向与将锁赋予等待时间最久的线程;公平锁即获取锁的顺序按先后调用lock方法的顺序(慎用);非公平锁即抢占的顺序不一定,看运气;synchronized是非公平锁。
ReentrantLock将锁对象化:判断是否有线程,或者某个特定的线程在排队等待获取锁;带超时的获取锁的尝试;能感知有没有成功获取锁。
总结:synchronzied是关键字,ReentrantLock是类;ReentrantLock可以对对获取锁的时间进行设置,避免线程死锁;ReentrantLock可以获取各种锁的信息;ReentrantLock可以灵活的实现多路通知;锁的机制不同:sync操作的是Mark Word,ReentrantLock调用的是Unsafe类的park()方法。
为什么要使用线程池:降低资源消耗,提高线程的可管理性。
ThreadPoolExecutorThreadPoolExecutor的构造函数:
线程池的状态: