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中的线程--线程的互斥与同步通信的更多相关文章

  1. Java中的守护线程 & 非守护线程(简介)

    Java中的守护线程 & 非守护线程 守护线程 (Daemon Thread) 非守护线程,又称用户线程(User Thread) 用个比较通俗的比如,任何一个守护线程都是整个JVM中所有非守 ...

  2. Java中如何创建线程

    Java中如何创建线程 两种方式:1)继承Thread类:2)实现Runnable接口. 1.继承Thread类 继承Thread类,重写run方法,在run方法中定义需要执行的任务. class M ...

  3. 关于Java中进程和线程的详解

    一.进程:是程序的一次动态执行,它对应着从代码加载,执行至执行完毕的一个完整的过程,是一个动态的实体,它有自己的生命 周期.它因创建而产生,因调度而运行,因等待资源或事件而被处于等待状态,因完成任务而 ...

  4. Java中怎样创建线程安全的方法

    面试问题: 下面的方法是否线程安全?怎样让它成为线程安全的方法? class MyCounter { private static int counter = 0; public static int ...

  5. ThreadLocal,Java中特殊的线程绑定机制

    在DRP项目中,我们使用了ThreadLocal来创建Connection连接,避免了一直以参数的形式将Connection向下传递(传递connection的目的是由于jdbc事务要求确保使用同一个 ...

  6. Java中的守护线程和非守护线程(转载)

    <什么是守护线程,什么是非守护线程> Java有两种Thread:"守护线程Daemon"(守护线程)与"用户线程User"(非守护线程). 用户线 ...

  7. Java中的守护线程

    守护线程的概念 在java中有两种线程,守护线程和非守护线程,其两者并没有本质的区别,唯一的区别就是当前的用户线程退出的时候,若只存在唯一的A线程,若A线程为守护线程,那么JVM将会直接退出,否则JV ...

  8. (转)Java中的守护线程

    Java的守护线程与非守护线程   守护线程与非守护线程 最近在看多线程的Timer章节,发现运用到了守护线程,感觉Java的基础知识还是需要补充. Java分为两种线程:用户线程和守护线程 所谓守护 ...

  9. Java中的守护线程——daemon

    絮叨 Java中有两类线程:User Thread(用户线程).Daemon Thread(守护线程) 定义:守护线程(aka:服务线程),在没有用户线程可服务时会自动离开. 优先级:守护线程的优先级 ...

  10. Java-ThreadLocal,Java中特殊的线程绑定机制

    在DRP项目中,我们使用了ThreadLocal来创建Connection连接,避免了一直以参数的形式将Connection向下传递(传递connection的目的是由于jdbc事务要求确保使用同一个 ...

随机推荐

  1. Python 3.x 的一些注意事项

    1. reload 被更改 需要 在console执行 from imp import reload 才能调用CT 同时,如果py文件是位于主文件夹深部的位置,可以这么做: import ComicT ...

  2. 洛谷CF895C Square Subsets(线性基)

    洛谷传送门 不知道线性基是什么东西的可以看看蒟蒻的总结 题意: 给你n个数,每个数<=70,问有多少个集合,满足集合中所有数相乘是个完全平方数(空集除外) 题解: 完全看不出这玩意儿和线性基有什 ...

  3. 五粮液【线段树】By cellur925

    题目传送门 考场上感觉的确是线段树,还要维护区间最值...最值怎么维护?还要区间修改?\(update\)的时候加一下就好了吧...之后怎么搞啊?\(qwqwq\)之后好像不太会了...果断删除几乎快 ...

  4. ADO学途 five day 连接数据库

    用一个程序的目的就是为了方便对数据进行操作,没有数据的支持,程 序就成了一个空壳子.一般我们常用的数据库有三种mysql, SQL server, Oracle. C#中常用的就是SQL server ...

  5. Nginx 405 not allowed最简单快速解决办法

    Apache.IIS.Nginx等绝大多数web服务器,都不允许静态文件响应POST请求,否则会返回“HTTP/1.1 405 Method not allowed”错误. server { list ...

  6. G - You Are the One(需要重想一遍)

    #include <iostream> #include <algorithm> #include <cstring> #include <cstdio> ...

  7. 牛客寒假6-E.海啸

    链接:https://ac.nowcoder.com/acm/contest/332/E 题意: 有一个沿海地区,可以看作有n行m列的城市,第i行第j列的城市海拔为h[i][j]. 由于沿海,所以这个 ...

  8. 最大xor,and,or

    http://210.33.19.103/contest/998 and,or部分 并不用01trie,题目&题解:https://blog.csdn.net/dreaming__ldx/ar ...

  9. while嵌套应用二:九九乘法表

    __author__ = 'zht' #!/usr/bin/env python # -*- coding: utf-8 -*- ''' #努力学习每一天 ''' #while嵌套应用二:九九乘法表 ...

  10. Warning: skipping non-radio button in group

    Question:   最近在开发中,设计了一个对话框来进行一系列的设定,其中有一组Radio Buttons(单选按钮),但在Debug下,发现对话的弹出有点延迟,经过分析,确定是因为在对话框弹出之 ...