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事务要求确保使用同一个 ...
随机推荐
- Python 3.x 的一些注意事项
1. reload 被更改 需要 在console执行 from imp import reload 才能调用CT 同时,如果py文件是位于主文件夹深部的位置,可以这么做: import ComicT ...
- 洛谷CF895C Square Subsets(线性基)
洛谷传送门 不知道线性基是什么东西的可以看看蒟蒻的总结 题意: 给你n个数,每个数<=70,问有多少个集合,满足集合中所有数相乘是个完全平方数(空集除外) 题解: 完全看不出这玩意儿和线性基有什 ...
- 五粮液【线段树】By cellur925
题目传送门 考场上感觉的确是线段树,还要维护区间最值...最值怎么维护?还要区间修改?\(update\)的时候加一下就好了吧...之后怎么搞啊?\(qwqwq\)之后好像不太会了...果断删除几乎快 ...
- ADO学途 five day 连接数据库
用一个程序的目的就是为了方便对数据进行操作,没有数据的支持,程 序就成了一个空壳子.一般我们常用的数据库有三种mysql, SQL server, Oracle. C#中常用的就是SQL server ...
- Nginx 405 not allowed最简单快速解决办法
Apache.IIS.Nginx等绝大多数web服务器,都不允许静态文件响应POST请求,否则会返回“HTTP/1.1 405 Method not allowed”错误. server { list ...
- G - You Are the One(需要重想一遍)
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> ...
- 牛客寒假6-E.海啸
链接:https://ac.nowcoder.com/acm/contest/332/E 题意: 有一个沿海地区,可以看作有n行m列的城市,第i行第j列的城市海拔为h[i][j]. 由于沿海,所以这个 ...
- 最大xor,and,or
http://210.33.19.103/contest/998 and,or部分 并不用01trie,题目&题解:https://blog.csdn.net/dreaming__ldx/ar ...
- while嵌套应用二:九九乘法表
__author__ = 'zht' #!/usr/bin/env python # -*- coding: utf-8 -*- ''' #努力学习每一天 ''' #while嵌套应用二:九九乘法表 ...
- Warning: skipping non-radio button in group
Question: 最近在开发中,设计了一个对话框来进行一系列的设定,其中有一组Radio Buttons(单选按钮),但在Debug下,发现对话的弹出有点延迟,经过分析,确定是因为在对话框弹出之 ...