一、synchronized关键字
在多线程中,在资源共享的情况下会出现安全问题
- 使用Runnable接口实现多线程。
- 创建RunnableTest类,并创建nums私有资源,设置为100
- 重写run方法,在方法中通过while死循环减少资源
- 创建测试类RunnableDemo对象,在这里创建两个线程,执行同一资源
public class RunnableDemo implements Runnable {
private int nums = 30;
@Override
public void run() {
while (true) {
if(nums < 0) {
break;
} else {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
nums--;
System.out.println(Thread.currentThread().getName()+"的mus的值为"+nums);
}
}
}
}
public class RunnableTest {
public static void main(String[] args) {
// 创建参数的对象
RunnableDemo rb1 = new RunnableDemo();
// 创建线程对象并传递参数
Thread t1 = new Thread(rb1);
Thread t2 = new Thread(rb1);
// 设置线程名称
t1.setName("线程1");
t2.setName("线程2");
// 开启线程
t1.start();
t2.start();
}
}
- 执行结果
同步代码块
通过给代码加锁,让它在同一时间最多一个线程执行这段代码,另外一个等待,上一个线程执行完之后,再执行下一个线程。
它包括两种用法:synchronized 方法和 synchronized 块。可用来给对象和方法或者代码块加锁。当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码
public class RunnableDemo implements Runnable {
private int nums = 30;
private Object obj = new Object();
@Override
public void run() {
synchronized (obj) {
while (true) {
if(nums <= 0) {
break;
} else {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
nums--;
System.out.println(Thread.currentThread().getName()+"的mus的值为"+nums);
}
}
}
}
}
public class RunnableTest {
public static void main(String[] args) {
// 创建参数的对象
RunnableDemo rb1 = new RunnableDemo();
// 创建线程对象并传递参数
Thread t1 = new Thread(rb1);
Thread t2 = new Thread(rb1);
// 设置线程名称
t1.setName("线程1");
t2.setName("线程2");
// 开启线程
t1.start();
t2.start();
}
}
- 执行结果如下
再修改
如果创建两个参数对象,创建两个线程对象,再次执行线程,这里将nums设置为静态变量,同时Obj也设置为静态变量
public class RunnableDemo implements Runnable {
private static int nums = 30;
private static Object obj = new Object();
@Override
....
}
public class RunnableTest {
public static void main(String[] args) {
// 创建参数的对象
RunnableDemo rb1 = new RunnableDemo();
RunnableDemo rb2 = new RunnableDemo();
// 创建线程对象并传递参数
Thread t1 = new Thread(rb1);
Thread t2 = new Thread(rb2);
// 设置线程名称
t1.setName("线程1");
t2.setName("线程2");
// 开启线程
t1.start();
t2.start();
}
}
- 执行结果
同步方法
就是将synchronized关键字加载静态方法上,如下
public class RunnableDemo implements Runnable {
private int nums = 30;
@Override
public void run() {
while (true) {
if ("1".equals(Thread.currentThread().getName())) {
boolean rs = syncMethod();
if (rs) {
break;
}
}
if ("2".equals(Thread.currentThread().getName())) {
synchronized (this) {
if (nums == 0) {
break;
} else {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
nums--;
System.out.println(Thread.currentThread().getName() + "的mus的值为" + nums);
}
}
}
}
}
private synchronized boolean syncMethod() {
if (nums == 0) {
return true;
} else {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
nums--;
System.out.println(Thread.currentThread().getName() + "的mus的值为" + nums);
return false;
}
}
}
public class RunnableTest {
public static void main(String[] args) {
// 创建参数的对象
RunnableDemo rb1 = new RunnableDemo();
// 创建线程对象并传递参数
Thread t1 = new Thread(rb1);
Thread t2 = new Thread(rb1);
// 设置线程名称
t1.setName("1");
t2.setName("2");
// 开启线程
t1.start();
t2.start();
}
}
二、Lock
- Lock可以实现类似synchronized的线程同步机制,
- 它更灵活,而且它不是一个关键字,是一个类
- 它需要手动释放锁,如果不释放,就会出现死锁现象
- lock可以配置公平策略,实现线程按照先后顺序获取锁
public class RunnableDemo implements Runnable {
private int nums = 30;
private ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
try {
lock.lock();
if (nums <= 0) {
break;
} else {
Thread.sleep(100);
nums--;
System.out.println(Thread.currentThread().getName() + "的mus的值为" + nums);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
public class RunnableTest {
public static void main(String[] args) {
// 创建参数的对象
RunnableDemo rb1 = new RunnableDemo();
// 创建线程对象并传递参数
Thread t1 = new Thread(rb1);
Thread t2 = new Thread(rb1);
// 设置线程名称
t1.setName("线程1");
t2.setName("线程2");
// 开启线程
t1.start();
t2.start();
}
}