目前所学过安全的类:
(1)Vector (多用于合并流)
(2)StringBuffer
(3)Hashtable
(4)Collections类中的:public static <T> List<T> synchronizedList(List<T> list)返回指定列表支持的同步(线程安全的)列表
1.检验多线程是否安全的标准:
(1)当前是否为多线程环境
(2)多线程环境中是否有共享数据
(3)是否有多条语句对共享数据进行操作
2.解决多线程不安全的方法(同步代码块):
将多条语句对共享数据的操作进行更改:使用同步代码块将对共享数据操作的代码包起来
格式:
(1)在成员位置声明同步锁对象(任意对象都可以)
(2)Synchronized(同步锁对象){
// 对共享数据进行操作的多条语句
}
3.同步锁对象要求
(1)可以是任意类(Object类以及任意自定义对象)
(2)同步方法:将Synchronized关键字至于方法声明,变成同步方法
①非静态方法:可以将Synchronized关键字加入到方法声明上,变成同步方法(同步锁对象为:this)
②静态方法:若同步方法为静态方法,需通过反射获取锁对象(锁对象为:当前类名.class)
4.同步机制解决线程安全问题的弊端
// 测试类
public class SellTicketTest {
public static void main(String[] args) {
// 创建SellTicket对象
SellTicket st = new SellTicket();
// 创建线程
Thread t1 = new Thread(st, "窗口1");
Thread t2 = new Thread(st, "窗口2");
Thread t3 = new Thread(st, "窗口3");
// 启动线程
t1.start();
t2.start();
t3.start();
}
}
// 自定义定义线程类
public class SellTicket implements Runnable {
// 定义共有数据100张票
private static int tickets = 100;
// 设置同步锁对象
Object obj = new Object();
@Override
public void run() {
// 假设一直有票
while(true) {
// 同步代码块:设置锁对象,一条线程进来之后会“关门”,别的线程不会再进来
synchronized (obj) {
// 让线程睡眠0.1秒
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票");
}
}
}
}
}
非同步方法:
// 自定义定义线程类
public class SellTicket implements Runnable {
// 定义共有数据100张票
private static int tickets = 100;
// 定义一个变量
private int i;
@Override
public void run() {
// 假设一直有票
while (true) {
if (i % 2 == 0) {
// 非静态方法this代表锁对象
synchronized (this) {
// 让线程睡眠0.1秒
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票");
}
}
} else {
sellTicket();
}
}
}
// 非静态同步方法
private synchronized void sellTicket() {
// 让线程睡眠0.1秒
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票");
}
}
}
静态同步方法:
// 自定义定义线程类
public class SellTicket implements Runnable {
// 定义共有数据100张票
private static int tickets = 100;
// 定义一个变量
private int i;
@Override
public void run() {
// 假设一直有票
while (true) {
if (i % 2 == 0) {
// 静态方法SellTicket.class代表锁对象
synchronized (SellTicket.class) {
// 让线程睡眠0.1秒
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票");
}
}
} else {
sellTicket();
}
i++;
}
}
// 静态同步方法
private static synchronized void sellTicket() {
// 让线程睡眠0.1秒
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票");
}
}
}
同步机制可能会出现的死锁现象:
// 测试类
public class DieLockTest {
public static void main(String[] args) {
// 创建线程类对象
DieLock dl1 = new DieLock(true);
DieLock dl2 = new DieLock(false);
// 启动线程
dl1.start();
dl2.start();
}
}
// 自定义锁
class MyLock {
//创建两把锁对象
public static final Object objA = new Object() ;
public static final Object objB = new Object() ;
}
// 自定义线程类
class DieLock extends Thread {
//定义一个成员变量
private boolean flag ;
public DieLock(boolean flag){
this.flag = flag ;
}
@Override
public void run() {
//dl1,dl2线程
if(flag){
synchronized(MyLock.objA){
System.out.println("if objA");
synchronized (MyLock.objB) {
System.out.println("if objB");
}
}//代码执行完毕,objA锁相当于才能被释放掉
}else {
//dl2
synchronized (MyLock.objB) {
System.out.println("else objB");
synchronized(MyLock.objA){
System.out.println("else objA");
}
}
}
}
}