描述:如果操作共享数据的代码完整的声明在一个方法中,我们不妨将此方法同步的
以题:创建三个窗口卖票,总票数为100张为例
一:使用同步方法解决实现Runnable接口的线程安全问题
根据上篇文章使用同步代码块的方法解决实现Runnable接口的线程安全问题代码如下:
class Window1 implements Runnable{
private int ticket = 100;
Object obj = new Object();
@Override
public void run() {
while (true){
synchronized (this){//此时的this:唯一的Window1的对象 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) {
Window1 w = new Window1();
Thread t1 = new Thread(w);
Thread t2 = new Thread(w);
Thread t3 = new Thread(w);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
我们将操作共享数据的代码完整的声明在一个方法
private synchronized void show(){
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);
ticket--;
}
}
整理一下,完整代码如下:
class Window1 implements Runnable {
private int ticket = 100;
@Override
public void run() {
while (true) {
show();
}
}
private 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 WindowTest1 {
public static void main(String[] args) {
Window1 w = new Window1();
Thread t1 = new Thread(w);
Thread t2 = new Thread(w);
Thread t3 = new Thread(w);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
在show方法中有一个默认的同步监视器“this”
模仿以上方法套用到使用同步方法处理继承Thread类的方法中的线程安全问题中,在继承Thread类创建多线程的代码中将操作共享数据的代码完整的声明在一个方法
代码如下:
class Window extends Thread {
private static int ticket = 100;
@Override
public void run() {
while (true) {
show();
}
}
private synchronized void show(){
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName() + "卖票,票号为:" + ticket);
ticket--;
}
}
}
public class WindowTest {
public static void main(String[] args) {
Window t1 = new Window();
Window t2 = new Window();
Window t3 = new Window();
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
运行结果如下;
扫描二维码关注公众号,回复:
15295962 查看本文章
我们可以看到还是出现的错票,这是因为上文提到的在show方法中有一个默认的同步监视器“this”在这个程序中我们创建了三个对象所以同步监视器:t1,t2,t3。然而多个线程必须要共用同一把锁(同步监视器)
我们可以把show方法改成静态的
class Window extends Thread {
private static int ticket = 100;
@Override
public void run() {
while (true) {
show();
}
}
private static synchronized void show(){//同步监视器:t1,t2,t3
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + ticket);
ticket--;
}
}
}
public class WindowTest {
public static void main(String[] args) {
Window t1 = new Window();
Window t2 = new Window();
Window t3 = new Window();
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
此时的同步监视器便是当前的这个类-->Window.class
=========================================================================总结:
1.同步方法仍然涉及到同步监视器,只是不需要我们显式的声明
2.非静态的同步方法,同步监视器是:this 静态的同步方法,同步监视器是:当前类的本身
感谢观看!!!