java学习线程篇之多线程的同步与死锁
1. 线程的同步产生原因
实际上所谓的同步就是多个线程访问同一资源时所需要考虑到的情况。
import java.io.PrintStream;
class MyThead implements Runnable { //这就是一个多线程的操作类
private int price=5;
@Override
public void run(){ //覆写run方法,作为线程的主体操作方法
while (this.price>0) {
try {
Thread.sleep(100);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+": 降价后的价格: "+this.price--);
}
}
}
public class TestThr{
public static void main(String[] args) {
MyThead myThead=new MyThead();
new Thread(myThead,"线程A").start();
new Thread(myThead,"线程B").start();
new Thread(myThead,"线程C").start();
new Thread(myThead,"线程D").start();
}
}
线程不同步问题导致出现了负的价格。。。
2. 线程的同步处理操作
通过观察可以发现以上程序带来的最大问题在:判断和修改数据是分开完成的,即多个线程可以同时执行这些功能。
所谓的同步就是指多个操作在同一时间段内只能有一个线程进行,其他线程要等待此线程完成之后才可以继续执行。
在java里面要想实现线程的同步可以使用synchronized关键字。而这个关键字可以通过两种方式使用:
- 同步代码块
- 同步方法
在Java里面有四种代码块,即:普通代码块,构造块,静态块,同步块。
使用同步代码块解决:
使用以下测试代码实际上更合适:
import java.io.PrintStream;
class MyThead implements Runnable { //这就是一个多线程的操作类
private int price=100;
@Override
public void run() { //覆写run方法,作为线程的主体操作方法
//synchronized (this) {
for (int i = 0; i < 50; i++) {
if (this.price > 0) {
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ": 降价后的价格: " + this.price--);
}
}
}
}
//}
public class TestThr{
public static void main(String[] args) {
MyThead myThead=new MyThead();
new Thread(myThead,"线程A").start();
new Thread(myThead,"线程B").start();
new Thread(myThead,"线程C").start();
new Thread(myThead,"线程D").start();
}
}
使用同步方法解决:
同步操作与异步操作相比,异步操作的执行速度要高于同步操作,但同步操作时数据安全性较高,属于安全的线程操作。
3. 线程的死锁情况
实际上通过分析可以发现,所谓的同步就是指一个线程对象等待另外一个线程对象执行完毕后的操作形式。
线程同步过多就可能造成死锁。
死锁:两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
public class TestDemo implements Runnable{
private static A a=new A();
private static B b=new B();
public static void main(String[] args) throws Exception {
new TestDemo();
}
public TestDemo(){
new Thread(this).start();
b.say(a);
}
@Override
public void run() {
a.say(b);
}
}
class A{
public synchronized void say(B b){
System.out.println("把你的笔给我,我就给你本");
b.get();
}
public synchronized void get(){
System.out.println("拿到了笔");
}
}
class B{
public synchronized void say(A a){
System.out.println("把你的本给我,我就给你笔");
a.get();
}
public synchronized void get() {
System.out.println("拿到了本");
}
}
以上的代码说明死锁存在。死锁是程序开发中由于某种逻辑上的错误所造成的问题,并且不是简单的就会出现的。
面试题:请解释多个线程访问同一资源时需要考虑哪些情况?有可能带来哪些问题?
- 多个线程访问同一资源时一定要处理好同步问题,可以使用同步代码块、同步方法解决;
- 同步代码块: synchronized (锁定对象) {代码}
- 同步方法: public synchronized 返回值 方法名称() {代码}
- 但是过多的使用同步有可能造成死锁。
4. 总结
- 死锁是一种不定的状态。
- 最简单的理解同步和异步的操作可以通过synchronized来实现。