方法一:
同步代码块:
synchronized(同步监视器){
需要被同步的代码块
}
注意:
- 操作共享数据的代码,即为同步代码块。
- 共享数据:即多个线程共同操作的变量。
- 同步监视器:也称作“锁”,任何一个类的对象,都可以充当这个锁。但是多个线程必须共用同一把锁。
- 在实现Runnable接口创建多线程的方式中,我们可以考虑用this来充当同步监视器。
代码实现:
/**
* @author panghu
* @description 实现Runnable接口方式实现线程安全多窗口卖票
* @create 2021-01-06-14:44
*/
public class TicketWindowTest1 {
public static void main(String[] args) {
TicketWindow w1 = new TicketWindow();
Thread t1 = new Thread(w1);
Thread t2 = new Thread(w1);
Thread t3 = new Thread(w1);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
class TicketWindow implements Runnable {
private int ticket = 100;
// 同步代码块
@Override
public void run() {
while (true) {
synchronized (this) {
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + ":" + ticket);
ticket--;
try {
Thread.currentThread().sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
break;
}
}
}
}
}
/**
* @author panghu
* @description 继承Thread类的方式实现线程安全的多窗口售票
* @create 2021-01-06-15:20
*/
public class TicketWindowsTest2 {
public static void main(String[] args) {
TicketWindow2 w1 = new TicketWindow2();
TicketWindow2 w2 = new TicketWindow2();
TicketWindow2 w3 = new TicketWindow2();
w1.setName("窗口1");
w2.setName("窗口2");
w3.setName("窗口3");
w1.start();
w2.start();
w3.start();
}
}
class TicketWindow2 extends Thread {
private static int ticket = 100;
// private static Object obj = new Object();
// 同步代码块
@Override
public void run() {
while (true) {
//synchronized (obj){
synchronized (TicketWindow2.class){
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + ":" + ticket);
ticket--;
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
break;
}
}
}
}
}
方法二:同步方法
如果操作共享数据的代码完整的声明在了一个方法中,那么我们也可以通过同步方法的方式来实现线程安全。
代码实现:
/**
* @author panghu
* @description 实现Runnable接口方式实现线程安全多窗口卖票
* @create 2021-01-06-14:44
*/
public class TicketWindowTest1 {
public static void main(String[] args) {
TicketWindow w1 = new TicketWindow();
Thread t1 = new Thread(w1);
Thread t2 = new Thread(w1);
Thread t3 = new Thread(w1);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
class TicketWindow implements Runnable {
private int ticket = 100;
// 同步方法
@Override
public void run() {
while (true) {
sellTicket();
}
}
private synchronized void sellTicket(){
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + ":" + ticket);
ticket--;
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* @author panghu
* @description 继承Thread类的方式实现线程安全的多窗口售票
* @create 2021-01-06-15:20
*/
public class TicketWindowsTest2 {
public static void main(String[] args) {
TicketWindow2 w1 = new TicketWindow2();
TicketWindow2 w2 = new TicketWindow2();
TicketWindow2 w3 = new TicketWindow2();
w1.setName("窗口1");
w2.setName("窗口2");
w3.setName("窗口3");
w1.start();
w2.start();
w3.start();
}
}
class TicketWindow2 extends Thread {
private static int ticket = 100;
// 同步方法
@Override
public void run() {
while (true) {
sellTicket();
}
}
// 方法声明为静态的,同步监视器为TicketWindow2.class
// 否则同步监视器为实例化的多个对象
private static synchronized void sellTicket() {
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + ":" + ticket);
ticket--;
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}