Java中的线程--线程的互斥与同步通信
Java中的线程之前也提到过,但是还是想再详细的学习一下,跟着张孝祥老师,系统的再学习一下。
一、线程中的互斥
线程安全中的问题解释:线程安全问题可以用银行中的转账
例题描述:
线程A与线程B分别访问同一个对象的方法,这样就会存在线程安全的问题,方法的作用是打印出字符串中的每一个字符,方法如下:
public void output(String name) {
int len = name.length();
for (int i = 0; i < len; i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
线程A和线程B代码如下:(直接写在了init()方法中了)
private void init() {
outputer outputer = new outputer();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
outputer.output("songshengchao");
}
}
}).start(); new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
outputer.output("songxiaochao");
}
}
}).start();
}
测试一下,肯定会出现线程不安全的问题,这是母庸质疑的事实,测试代码如下:
public static void main(String[] args) {
new TraditionalThreadSynchronized().init();
}
三种解决办法,代码如下:
public class outputer {
public void output(String name) {
int len = name.length();
synchronized (this) { // 传进来当前调用方法的对象,要求线程用的是同一个对象
//synchronized (outputer.class) { // 这样和outputer3方法达到线程互斥
for (int i = 0; i < len; i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
} // 方法上的锁对象用的就是this当前对象
public synchronized void output2(String name) {
int len = name.length();
for (int i = 0; i < len; i++) {
System.out.print(name.charAt(i));
}
System.out.println();
} // output3 想和output方法达到线程互斥
public static synchronized void output3(String name) {
int len = name.length();
for (int i = 0; i < len; i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
}
注意:至于第三种静态的synchronized方法,在和第一个方法共用时,第一种方法一定是用当前对象的class字节码文件,才能确保两个方法用的同一个对象。
二、线程互斥与通信的经典面试题
面试题:子线程循环10次,接着主线程循环100次,接着又回到子线程循环10次,接着在主线程循环100次,如此循环50次,程序如何写???
经验之谈,设计思想,设计思路:
要用到共同数据(包括同步锁)的若干个方法应该归在同一个类上,这种设计正好提现了程序的高内聚与健壮性
思路:先写主线程与子线程的循环,然后在考虑轮流执行。先考虑循环,代码如下:
public class TraditionalThreadCommunication { public static void main(String[] args) { new Thread(new Runnable() { @Override
public void run() {
for (int i = 1; i <= 50; i++) {
synchronized (TraditionalThreadCommunication.class) {
for (int j = 1; j <= 10; j++) {
System.out.println("sub thread sequece of" + j + ", loop of " + i);
}
} }
}
}).start(); // 本身main方法就是主线程,直接可以写循环代码
for (int i = 1; i <= 50; i++) {
synchronized (TraditionalThreadCommunication.class) {
for (int j = 1; j <= 100; j++) {
System.out.println("main thread sequece of" + j + ", loop of " + i);
}
}
} }
}
代码优化,用面向对象的思想,将那些代码放到一个公共的类中,然后执行类中的不同方法,优化成一个公共的类,代码如下:
public class Business { public synchronized void sub(int i){
for (int j = 1; j <= 10; j++) {
System.out.println("sub thread sequece of" + j + ", loop of " + i);
}
} public synchronized void main(int i){
for (int j = 1; j <= 100; j++) {
System.out.println("main thread sequece of" + j + ", loop of " + i);
}
}
} ---------------------------------------------------------------------------------------------- public class TraditionalThreadCommunication { public static void main(String[] args) {
Business business = new Business();
new Thread(new Runnable() { @Override
public void run() {
for (int i = 1; i <= 50; i++) {
business.sub(i);
}
}
}).start(); // 本身main方法就是主线程,直接可以写循环代码
for (int i = 1; i <= 50; i++) {
business.main(i);
} } }
最终的完整代码如下(详细注释):
public class Business { // 是否是子线程执行 默认子线程先执行
private boolean bShouldSub = true; public synchronized void sub(int i) {
// 不是子线程应该执行 让给主线程 子线程执行等待的方法
while (!bShouldSub) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int j = 1; j <= 10; j++) {
System.out.println("sub thread sequece of" + j + ", loop of " + i);
}
// 子线程执行完毕后 让给主线程执行
bShouldSub = false;
// 唤醒主线程
this.notify();
} public synchronized void main(int i) {
// 是子线程应该执行 让给子线程执行 主线程执行等待的方法
while (bShouldSub) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int j = 1; j <= 100; j++) {
System.out.println("main thread sequece of" + j + ", loop of " + i);
}
// 主线程执行费完毕后 交给子线程执行
bShouldSub = true;
// 唤醒子线程
this.notify();
}
}
------------------------------------------------------------------------------------------------ public class TraditionalThreadCommunication { public static void main(String[] args) {
Business business = new Business();
new Thread(new Runnable() { @Override
public void run() {
for (int i = 1; i <= 50; i++) {
business.sub(i);
}
}
}).start(); // 本身main方法就是主线程,直接可以写循环代码
for (int i = 1; i <= 50; i++) {
business.main(i);
} } }
Java中的线程--线程的互斥与同步通信的更多相关文章
- Java中的守护线程 & 非守护线程(简介)
Java中的守护线程 & 非守护线程 守护线程 (Daemon Thread) 非守护线程,又称用户线程(User Thread) 用个比较通俗的比如,任何一个守护线程都是整个JVM中所有非守 ...
- Java中如何创建线程
Java中如何创建线程 两种方式:1)继承Thread类:2)实现Runnable接口. 1.继承Thread类 继承Thread类,重写run方法,在run方法中定义需要执行的任务. class M ...
- 关于Java中进程和线程的详解
一.进程:是程序的一次动态执行,它对应着从代码加载,执行至执行完毕的一个完整的过程,是一个动态的实体,它有自己的生命 周期.它因创建而产生,因调度而运行,因等待资源或事件而被处于等待状态,因完成任务而 ...
- Java中怎样创建线程安全的方法
面试问题: 下面的方法是否线程安全?怎样让它成为线程安全的方法? class MyCounter { private static int counter = 0; public static int ...
- ThreadLocal,Java中特殊的线程绑定机制
在DRP项目中,我们使用了ThreadLocal来创建Connection连接,避免了一直以参数的形式将Connection向下传递(传递connection的目的是由于jdbc事务要求确保使用同一个 ...
- Java中的守护线程和非守护线程(转载)
<什么是守护线程,什么是非守护线程> Java有两种Thread:"守护线程Daemon"(守护线程)与"用户线程User"(非守护线程). 用户线 ...
- Java中的守护线程
守护线程的概念 在java中有两种线程,守护线程和非守护线程,其两者并没有本质的区别,唯一的区别就是当前的用户线程退出的时候,若只存在唯一的A线程,若A线程为守护线程,那么JVM将会直接退出,否则JV ...
- (转)Java中的守护线程
Java的守护线程与非守护线程 守护线程与非守护线程 最近在看多线程的Timer章节,发现运用到了守护线程,感觉Java的基础知识还是需要补充. Java分为两种线程:用户线程和守护线程 所谓守护 ...
- Java中的守护线程——daemon
絮叨 Java中有两类线程:User Thread(用户线程).Daemon Thread(守护线程) 定义:守护线程(aka:服务线程),在没有用户线程可服务时会自动离开. 优先级:守护线程的优先级 ...
- Java-ThreadLocal,Java中特殊的线程绑定机制
在DRP项目中,我们使用了ThreadLocal来创建Connection连接,避免了一直以参数的形式将Connection向下传递(传递connection的目的是由于jdbc事务要求确保使用同一个 ...
随机推荐
- CodeForces722C Destroying Array【瞎搞】
题意: 先给你一个序列,然后给你n个1-n的一个数,让你求前i个元素销毁的时候,区间字段和区间最大: 思路: 离线处理,维护新区间首尾位置的起点和终点,倒着处理: #include <bits/ ...
- POJ3737【数学】
高中数学题?初中吧///然后注意一下POJ的double输出用%f.......... #include <iostream> #include <stdio.h> #incl ...
- Dota2技能系统设计分析
http://blog.csdn.net/langresser_king/article/details/46776701 前两周写完了新游戏的技能系统.虽然也算灵活,但是跟Dota2的技能系统设计比 ...
- Unity NGUI学习
环境 Unity4.3 NGUI v3.68 导入 Project界面->右键->import package->custom package载入安装包即可 untiy4.6用 ...
- (转) Git
http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000
- python 的sorted函数
sorted函数:sorted(iterable,key,reverse) 其中iterable表示可以迭代的对象, key是一个函数,用来选取参与比较的元素,reverse则是用来指定排序是倒序还 ...
- Cstring的使用
https://msdn.microsoft.com/zh-cn/aa315043 1.字符串提取函数,CString::Left.CString::Mid .CString::Right CStri ...
- css-原理详解
语法 CSS 规则由两个主要的部分构成:选择器,以及一条或多条声明: 选择器一般使用id或者class选择器,声明由{}包含,每条声明由一个属性和一个值组成. .city { float:left; ...
- 2016级萌新选拔赛BE题
#include<bits/stdc++.h> using namespace std; #define ll long long ll a[]; ll d[]; int main() { ...
- 关于ssh的介绍
最近看到一篇关于介绍ssh讲得很清晰的文章,这里来记录一下加深一下印象: 基本原理: SSH(Secure Shell)是一套协议标准,可以用来实现两台机器之间的安全登录以及安全的数据传送,其保证数据 ...