多个线程在执行的过程中的不确定性引起执行结构的不稳定,同时多个线程对同一数据的共享操作,造成操作的不完整性,破坏数据。
当某个线程在操作车票过程中,尚未操作完成时,其他线程也参与进来,操作车票,使车票的数据共享,出现线程安全问题。
那么可以通过同步代码块和同步方法的方式来解决线程安全问题,实现线程的同步。
方式 1 . 同步代码块
1.1通过多线程继承方式实现代码块同步机制
public class ThreadTest extends Thread {
public static void main(String[] args) {
// 实例化窗口一对象
SaleTicket myThread1=new SaleTicket ();
// 实例化窗口二对象
SaleTicket myThread2=new SaleTicket ();
// 实例化窗口三对象
SaleTicket myThread3=new SaleTicket ();
// 窗口一的调用
myThread1.start();
// 窗口二的调用
myThread2.start();
// 窗口三的调用
myThread3.start();
}
}
class SaleTicket extends Thread{
// 定义类的对象,同步监视器,充当锁
public static Object obj=new Object();
// 定义静态变量,实现数据共享
public static int ticket=100;
@Override
public void run() {
while (true){
// 使用synchronized,包含被同步的代码
synchronized (obj){
if(ticket>0){
try {
// 调用睡眠方法,进行try-catch处理
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖票,票号为"+ticket);
ticket--;
}else{
break;
}
}
}
}
}
1.2通过实现Runnable接口方式实现代码块同步机制
class SaleTicket implements Runnable{
private int ticket=100;
// 定义监视器类
Object obj=new Object();
@Override
public void run() {
while (true){
// synchronized同步机制,包含被同步代码
synchronized (obj){
if(ticket>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖票,票号为"+ticket);
ticket--;
}else{
break;
}
}
}
}
}
public class windowTest1 {
public static void main(String[] args) {
// 实例化saleTicket对象
SaleTicket saleTicket=new SaleTicket ();
// 创建Thread类的对象,传递对象值
Thread test=new Thread(saleTicket);
Thread test1=new Thread(saleTicket);
Thread test2=new Thread(saleTicket);
// 设置窗口名
test.setName("窗口1");
test1.setName("窗口2");
test2.setName("窗口3");
// 窗口一的调用方法
test.start();
// 窗口二的调用
test1.start();
// 窗口三的调用
test2.start();
}
}
方式 2 . 同步方法
2.1多线程继承方式和同步方法结合,实现同步机制
public class WindowTest4 {
public static void main(String[] args) {
// 实例化窗口一对象
SaleTicket myThread1=new SaleTicket ();
// 实例化窗口二对象
SaleTicket myThread2=new SaleTicket ();
// 实例化窗口三对象
SaleTicket myThread3=new SaleTicket ();
// 窗口一的调用
myThread1.start();
// 窗口二的调用
myThread2.start();
// 窗口三的调用
myThread3.start();
}
}
class SaleTicket extends Thread{
public static int ticket=100;
@Override
public void run() {
while (true){
// 调用show方法
show();
}
}
// 通过 static show方法,实现synchronized,这里不再需要同步监视器
private static synchronized void show(){
if(ticket>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖票,票号为"+ticket);
ticket--;
}
}
}
2.2多线程实现Runnable接口方式和同步方法结合,实现同步机制
class Window1 implements Runnable {
private int ticket = 100;
@Override
public void run() {
while (true) {
// 调用show方法
show();
}
}
// 通过show方法,实现synchronized
public synchronized void show() {
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖票,票号为" + ticket);
ticket--;
}
}
}
public class windowTest3 {
public static void main(String[] args) {
// 实例化saleTicket对象
SaleTicket saleTicket=new SaleTicket ();
// 创建Thread类的对象,传递对象值
Thread test=new Thread(saleTicket);
Thread test1=new Thread(saleTicket);
Thread test2=new Thread(saleTicket);
// 设置窗口名
test.setName("窗口1");
test1.setName("窗口2");
test2.setName("窗口3");
// 窗口一的调用方法
test.start();
// 窗口二的调用
test1.start();
// 窗口三的调用
test2.start();
}
}
总结:
1.在非静态的同步代码块中,同步监视器可以是this,对于静态的同步代码块中,同步监视器可以是当前类本身
private int ticket=100;
@Override
public void run() {
while (true){
// 非静态方法中,可以使用this
synchronized (this){
if(ticket>0){
// 被同步的代码
}
}
public static int ticket=100;
@Override
public void run() {
while (true){
// 静态方法中是当前类本身,不在定义同步监视器类的对象
synchronized (myThread1.class){
if(ticket>0){
// 被同步的代码
}
}
2.在同步方法中仍然设计到同步监视器,在这里我们不需要在显示的声明