线程安全问题都是由全局变量及静态变量引起的。若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。
方式一:使用Runnable接口
/**
* 例子:创建三个窗口买票,总票数为100张 ——> 使用实现Runnable接口的方式
*/
class Window1 implements Runnable{
private int ticket = 10000;
@Override
public void run() {
while(true){
if(ticket > 0){
System.out.println(Thread.currentThread().getName() + ":买票,票号为:" + ticket);
ticket--;
}else {
break;
}
}
}
}
public class WindowTest {
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();
}
}
方式二:使用线程同步机制(线程安全处理Synchronized,只有一个锁)
线程同步的方式有两种:
方式1:同步代码块
方式2:同步方法
使用同步代码块
public class ThreadTest {
public static void main(String[] args) {
Ticket t = new Ticket();
Thread th1 = new Thread(t);
Thread th2 = new Thread(t);
Thread th3 = new Thread(t);
th1.setName("窗口1");
th2.setName("窗口2");
th3.setName("窗口3");
th1.start();
th2.start();
th3.start();
}
}
class Ticket implements Runnable{
// 定义票根
int ticket = 100;
Object lock = new Object();
@Override
public void run() {
while(true){
// synchronized中的的参数可以为任意对象
synchronized (lock) {
if(ticket > 0){
// 模拟选座的操作
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在卖票:" + ticket);
ticket--;
}else{
break;
}
}
}
}
}
使用同步方法
public class ThreadTest {
public static void main(String[] args) {
Ticket t = new Ticket();
Thread th1 = new Thread(t);
Thread th2 = new Thread(t);
Thread th3 = new Thread(t);
th1.setName("窗口1");
th2.setName("窗口2");
th3.setName("窗口3");
th1.start();
th2.start();
th3.start();
}
}
class Ticket implements Runnable{
// 定义票根
int ticket = 100;
@Override
public void run() {
while(true){
// 同步方法
boolean method = method();
if(method){
break;
}
}
}
// 同步方法中的锁对象是 this
// 静态同步方法中的锁对象是 类名.class
public synchronized boolean method() {
boolean flag = false;
if(ticket > 0){
// 模拟选座的操作
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在卖票:" + ticket);
ticket--;
}else{
flag = true;
}
return flag;
}
}