多线程的锁有: synchronized 和 jdk1.5的Lock
先说synchronized的各种用法:
1. 使用任意同一对象做锁 (一定要是同一对象)
2. 使用this做锁
3. class字节码文件做锁
4. 静态同步代码块做锁 (原理其实就是:class字节码文件做锁)
5.非静态同步代码块做锁 (原理其实就是:使用this做锁)
任意对象做锁例子:
/**
* @author: wangqinmin
* @date : 2020/7/3
* @description: 仰天大笑出门去,我辈岂是蓬蒿人
*/
public class TicketRunnable implements Runnable {
/**
* 需求现在有100张火车票,有两个窗口同时抢火车票,请使用多线程模拟抢票效果。
*/
int tickets = 100;
private Object obj = new Object();
public void run() {
while (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
sale();
}
}
public void sale() {
/**
* 使用任意、同一对象做锁
*/
synchronized (obj) {
/**
* 最后判断一下,还是因为有线程安全的问题。
*
* 最后一张票卖完后,tickets = 0,但是这时候,最后一个等待的线程刚刚就就进来了,所以会得到100 - 0 + 1 ,结果为101的票,所以在这里判断一下。
* 还有一个办法,就是在 while (tickets > 0) 之前就加 synchronized。
* 但是使用synchronized最好包裹的代码很少,所以就这样写了。
* 又如果在while那里就包裹了,多半这个代码直接就一个线程执行完了。
*/
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - tickets + 1) + "票");
tickets--;
}
}
}
}
this做锁的例子:
/**
* @author: wangqinmin
* @date : 2020/7/3
* @description: 仰天大笑出门去,我辈岂是蓬蒿人
*/
public class TicketRunnable implements Runnable {
/**
* 需求现在有100张火车票,有两个窗口同时抢火车票,请使用多线程模拟抢票效果。
*/
int tickets = 100;
public void run() {
while (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
sale();
}
}
public void sale() {
/**
* this做锁
*/
synchronized (this) {
/**
* 最后判断一下,还是因为有线程安全的问题。
*
* 最后一张票卖完后,tickets = 0,但是这时候,最后一个等待的线程刚刚就就进来了,所以会得到100 - 0 + 1 ,结果为101的票,所以在这里判断一下。
* 还有一个办法,就是在 while (tickets > 0) 之前就加 synchronized。
* 但是使用synchronized最好包裹的代码很少,所以就这样写了。
* 又如果在while那里就包裹了,多半这个代码直接就一个线程执行完了。
*/
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - tickets + 1) + "票");
tickets--;
}
}
}
}
class字节码文件做锁的例子:
/**
* @author: wangqinmin
* @date : 2020/7/3
* @description: 仰天大笑出门去,我辈岂是蓬蒿人
*/
public class TicketRunnable implements Runnable {
/**
* 需求现在有100张火车票,有两个窗口同时抢火车票,请使用多线程模拟抢票效果。
*/
int tickets = 100;
private Object obj = new Object();
public void run() {
while (tickets > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
sale();
}
}
public void sale() {
/**
* class文件做锁
*/
synchronized (TicketRunnable.class) {
/**
* 最后判断一下,还是因为有线程安全的问题。
*
* 最后一张票卖完后,tickets = 0,但是这时候,最后一个等待的线程刚刚就就进来了,所以会得到100 - 0 + 1 ,结果为101的票,所以在这里判断一下。
* 还有一个办法,就是在 while (tickets > 0) 之前就加 synchronized。
* 但是使用synchronized最好包裹的代码很少,所以就这样写了。
* 又如果在while那里就包裹了,多半这个代码直接就一个线程执行完了。
*/
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - tickets + 1) + "票");
tickets--;
}
}
}
}
静态同步代码块做锁: (并证明原理为 字节码文件为锁)
/**
* @author: wangqinmin
* @date : 2020/7/3
* @description: 仰天大笑出门去,我辈岂是蓬蒿人
*/
public class TicketRunnable implements Runnable {
/**
* 需求现在有100张火车票,有两个窗口同时抢火车票,请使用多线程模拟抢票效果。
* <p>
* 使用静态变量
*/
private static int tickets = 100;
private Object obj = new Object();
public void run() {
while (tickets > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (tickets % 2 != 0) {
synchronized (TicketRunnable.class) {
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - tickets + 1) + "票");
tickets--;
}
}
} else {
sale();
}
}
}
/**
* 定义静态同步代码块
* 在方法上,加上 static 和 synchronized。
* <p>
* 原理: 这个其实就是使用的字节码文件做锁。
* <p>
* 怎么证明呢 ? 可以写两个线程,一个使用字节码文件做锁,一个使用静态同步代码块,如果完成了同步功能,就证明静态同步代码快使用的是 字节码文件做锁。
* <p>
* 在工作中,不推荐使用静态同步锁,因为静态方法不会被回收。
* 建议使用 非静态同步代码块做锁;
*/
public static synchronized void sale() {
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - tickets + 1) + "票");
tickets--;
}
}
}
非静态同步代码块做锁:(并证明原理为: this做锁)
/**
* @author: wangqinmin
* @date : 2020/7/3
* @description: 仰天大笑出门去,我辈岂是蓬蒿人
*/
public class TicketRunnable implements Runnable {
/**
* 需求现在有100张火车票,有两个窗口同时抢火车票,请使用多线程模拟抢票效果。
* <p>
* 使用静态变量
*/
private int tickets = 100;
private Object obj = new Object();
public void run() {
while (tickets > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
/**
* 使用判断,证明非静态同步代码快使用的是this锁
*/
if (tickets % 2 != 0) {
synchronized (this) {
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - tickets + 1) + "票");
tickets--;
}
}
} else {
sale();
}
}
}
/**
* 定义非静态同步代码块
* 在方法上,加上 synchronized。
* <p>
* 原理: 这个其实就是使用的this锁。
* <p>
* 怎么证明呢 ? 可以写两个线程,一个使用this锁,一个使用非静态同步代码块,如果完成了同步功能,就证明非静态同步代码快使用的是this锁。
*/
public synchronized void sale() {
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - tickets + 1) + "票");
tickets--;
}
}
}
上面都是各种做锁的例子, 这里是创建多线程,并调用:
/**
* @author: wangqinmin
* @date : 2020/7/3
* @description: 仰天大笑出门去,我辈岂是蓬蒿人
*/
public class Test {
public static void main(String[] args) {
TicketRunnable ticket = new TicketRunnable();
Thread t1 = new Thread(ticket, "窗口1");
Thread t2 = new Thread(ticket, "窗口2");
t1.start();
t2.start();
}
}