Java并发 两个线程交替执行和死锁
今天看到一个题:两个线程交替打印奇数和偶数,即一个线程打印奇数,另一个打印偶数,交替打印从1到100。想了下有多重实现方法。
wait和notify方法:
public class OddEven {
private static int i = 1;
private static Object o = new Object();
private static class MyThread extends Thread {
MyThread(String name) {
super(name);
}
public void run() {
try {
synchronized (o) {
while (i < 100) {
System.out.println(this.getName() + i++);
o.notify();
o.wait();
}
o.notify();
}
System.out.println(this.getName() + " over");
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new MyThread("奇 ").start();
new MyThread("偶 ").start();
}
}
---
输出:
奇 1
偶 2
奇 3
偶 4
奇 5
偶 6
奇 7
...
LockSupport实现
public class OddEvenLockSupport {
private static int i = 1;
private static Thread t1 = new MyThread1();
private static Thread t2 = new MyThread2();
public static void main(String[] args) {
t1.start();
t2.start();
}
private static class MyThread1 extends Thread {
@Override
public void run() {
while (i < 51) {
System.out.println("奇 " + i++);
LockSupport.unpark(t2);
LockSupport.park();
}
System.out.println(getName() + " over");
LockSupport.unpark(t2);
}
}
private static class MyThread2 extends Thread {
@Override
public void run() {
while (i < 51) {
LockSupport.park();//顺序很重要
System.out.println("偶 " + i++);
LockSupport.unpark(t1);
}
System.out.println(getName() + " over");
LockSupport.unpark(t1);
}
}
}
---
使用Condition
public class OddEven2 {
private static Lock lock = new ReentrantLock();
static Condition even_c = lock.newCondition();
static Condition odd_c = lock.newCondition();
private static class Odd extends Thread {
public void run() {
int odd = 1;
try {
lock.lock();
while (odd < 100) {
System.out.println("奇 " + odd);
odd += 2;
even_c.signal();
odd_c.await();
}
System.out.println("奇 over");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
even_c.signal();
lock.unlock();
}
}
}
private static class Even extends Thread {
public void run() {
int even = 0;
try {
lock.lock();
while (even < 100) {
System.out.println("偶 " + even);
even += 2;
odd_c.signal();
even_c.await();
}
System.out.println("偶 over");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
odd_c.signal();
lock.unlock();
}
}
}
public static void main(String[] args) {
new Even().start();
new Odd().start();
}
}
---
另一个题,写出会导致死锁的代码:
public class DeadLock extends Thread {
private Object lock1;
private Object lock2;
public DeadLock(Object o1, Object o2) {
this.lock1 = o1;
this.lock2 = o2;
}
public void run() {
synchronized (lock1) {
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2) {
Q.p("end");
}
}
}
public static void main(String[] args) {
Object o1 = new Object(), o2 = new Object();
new DeadLock(o1, o2).start();
new DeadLock(o2, o1).start();
Q.p("main end");
}
}
---
基础回顾:
每个Java对象都拥有一个锁标记,即monitor(监视器),称为对象锁。
wait:
调用obj.wait()方法会阻塞当前线程,直到另一线程调用obj.notify()或obj.notifyAll()方法,其中obj为同一对象,当前线程必须持有obj对象锁,即必须在synchronized方法或代码块中,否则抛出IllegalMonitorStateException。调用wait方法的线程会释放对象锁。
notify:
唤醒一个正在等待该对象锁的线程,若有多个线程都在等待也只会唤醒一个。被唤醒的线程无法立即执行,直到当前线程放弃该对象锁,然后被唤醒的线程会像往常一样与任何其他线程竞争该对象锁,
该方法也必须在持有该对象锁的线程里调用,即必须在synchronized方法或代码块中,否则抛出IllegalMonitorStateException。
synchronized:
synchronized关键字标记一个方法或者代码块,当某个线程调用该对象的synchronized方法或者访问synchronized代码块时,这个线程便获得了该对象的锁,其他线程暂时无法访问这个方法,只有等待这个方法执行完毕或者代码块执行完毕,这个线程才会释放该对象的锁,其他线程才能执行这个方法或者代码块。
end
Java并发 两个线程交替执行和死锁的更多相关文章
- 简单的线程同步问题:两个线程交替执行N次【Synchronized、Lock、ArrayBlockingQueue】
方法一:传统的线程方法import org.apache.log4j.Logger; /** * 两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象.<br/> * ...
- 面试必问!Java 多线程中两个线程交替执行,一个输出偶数,一个输出奇数
前言 楼主今天在面经上看到这个题,挺有意思,小小的题目对多线程的考量还挺多.大部分同学都会使用 synchronized 来实现.楼主今天带来另外两种优化实现,让你面试的时候,傲视群雄! 第一种 sy ...
- 使用Java线程并发库实现两个线程交替打印的线程题
背景:是这样的今天在地铁上浏览了以下网页,看到网上一朋友问了一个多线程的问题.晚上闲着没事就决定把它实现出来. 题目: 1.开启两个线程,一个线程打印A-Z,两一个线程打印1-52的数据. 2.实现交 ...
- Java并发编程:线程间协作的两种方式:wait、notify、notifyAll和Condition
Java并发编程:线程间协作的两种方式:wait.notify.notifyAll和Condition 在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者 ...
- 19、Java并发编程:线程间协作的两种方式:wait、notify、notifyAll和Condition
Java并发编程:线程间协作的两种方式:wait.notify.notifyAll和Condition 在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者 ...
- Java 并发编程:线程间的协作(wait/notify/sleep/yield/join)
Java并发编程系列: Java 并发编程:核心理论 Java并发编程:Synchronized及其实现原理 Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) Java 并发编程 ...
- Java并发编程:线程池的使用
Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...
- Java并发编程:线程池的使用(转)
Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...
- Java并发编程:线程控制
在上一篇文章中(Java并发编程:线程的基本状态)我们介绍了线程状态的 5 种基本状态以及线程的声明周期.这篇文章将深入讲解Java如何对线程进行状态控制,比如:如何将一个线程从一个状态转到另一个状态 ...
随机推荐
- linux下安装LAMP环境,也就是PHP+linux的开发运行环境(centos7)
注:整理至http://blog.51cto.com/afterdawn/1923139 LAMP(linux.apache.mysql.php),是四个套件的合成,简单讲就是要把php运行在linu ...
- 最长公共子序列的C++实现---附二维指针的使用方法
想了挺久到底第一篇在这儿的博客写什么好,刚好这两天又一次看到动态规划的LCS算法觉得还是有点意思的,就拿来写了写,第一篇博客就发它吧. #include<iostream> #includ ...
- 在unity 中,使用http请求,下载文件到可读可写路径
在这里我用了一个线程池,线程池参数接收一个带有object参数的,无返回值的委托 ,下载用到的核心代码,网上拷贝的,他的核心就是发起一个web请求,然后得到请求的响应,读取响应的流 剩下的都是常见的I ...
- 0x5C 计数类DP
cf 559C 考虑到黑色的格子很少,那么我把(1,1)变成黑色,然后按每个黑色格子接近终点的程度排序,计算黑色格子不经过另一个黑色格子到达终点的方案,对于当前的格子,要减去在它右下角的所有方案数(注 ...
- Eclipse 换主题、皮肤、配色,换黑色主题护眼
Eclipse写android代码时,默认的文本和框架都是白色,长时间使用,显得过于刺眼.这里介绍三种方法换黑色护眼配色. 1.系统设置里更改 2.从Eclipse Marketplace里下载主题 ...
- 多校hdu5738 寻找
这道题前面给了两个公式,其实仔细分析一下,就会发现其实是给了你一堆点的坐标,然后让你求这些点有多少种组合可以形成共线的情况当两个点在一个坐标上时这两个点可以看做是不同的两个点,也就是说如果两个点在一个 ...
- RPC与HTTP
一.为什么需要RPC,而不是简单的HTTP接口? RPC(即Remote Procedure Call,远程过程调用),主要是基于TCP/IP协议:而HTTP服务主要是基于HTTP协议的.我们都知道H ...
- 把已安装的wampserver移动到不同目录使用应注意的问题
很多时候需要把已安装的wampserver移动到不同目录使用,此时应注意几个问题: 1.修改D:\wamp64\bin\apache\apache2.4.9\conf目录下的httpd.conf文件( ...
- Anton and School - 2 (组合数学)
题意:给你一串只有‘(’与‘)’的字符串,问你多少对括号,括号一定是左边一半的‘(’,右边一半是‘)’ )(()() 答案是:6 题解:枚举每个‘(’,此时设左括号左边有n个‘(’,它右边有m个‘ ...
- Android fill_parent和wrap_content分析
fill_parent设置一个顶部布局或控件强制性让它布满整个屏幕.(这是不管内容大小,直接适应整个屏幕的大小,例长度设置了这,就只有长度适应屏幕的长度) wrap_content布局指根据视图内部内 ...