最好不适用线程的子线程,直接调用线程,然后用rannable接口

然后如果要公用一个参数,就是公用资源的时候,一定要在run方法的前面加上synchronized

例子

猫和狗喝同一杯水(共用资源的问题)

/**
* @author nienie
*
*/ public class test { /**
* @param args
*/
public static void main(String[] args) {
// TODO 自动生成的方法存根
test1 test2 = new test1();
int n=10;
test2.setW(n);
System.out.println("一共" +n +"克水,dog和cat每次喝1克水");
Thread dog,cat;
dog = new Thread(test2);
cat = new Thread(test2);
dog.setName("dog");
cat.setName("cat");
dog.start();
cat.start();
} }
public class test1 implements Runnable{
int w = 10;
public void setW(int n){
w = n;
}
public synchronized void run() {
String name = Thread.currentThread().getName();
while(name.equals("dog")){
w = w-1;
System.out.println(name+" 喝水,剩下 "+w+ " 克"); notify();
try {
wait();
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
if(w==0) System.exit(0);
}
while(name.equals("cat")){
w = w-1;
System.out.println(name+" 喝水,剩下 "+w + " 克");
notify();
try {
wait();
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
if(w==0) System.exit(0);
}
}
}

运行结果

一共10克水,dog和cat每次喝1克水
dog 喝水,剩下 9 克
cat 喝水,剩下 8 克
dog 喝水,剩下 7 克
cat 喝水,剩下 6 克
dog 喝水,剩下 5 克
cat 喝水,剩下 4 克
dog 喝水,剩下 3 克
cat 喝水,剩下 2 克
dog 喝水,剩下 1 克
cat 喝水,剩下 0 克

这里要注意的是一定要有那个synchronized,这个的作用相当于一个锁,锁定某一个线程先做好,但是如果直接使用,有一个矛盾,就是无法实现两个线程交替地使用,这个会导致等这个线程结束了之后,然后再执行第二个线程,哪怕有sleep也不行的,所以这里就灵活的使用wait()方法,这个函数会将这个线程停止,然后让出cpu,让cpu执行其他线程,但是有一点要注意的是,在执行了wait之后,要使用notify方法激活另外的线程,不然的话,就会导致全部的线程都停止,然后程序就停下来了。

没有synchronized的情况

public class test1 implements Runnable{
int w = 10;
public void setW(int n){
w = n;
}
public void run() {
String name = Thread.currentThread().getName();
while(name.equals("dog")){
w = w-1;
System.out.println(name+" 喝水,剩下 "+w+ " 克");
notify();
try {
Thread.sleep(1000);
wait();
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
if(w==0) System.exit(0);
}
while(name.equals("cat")){
w = w-1;
System.out.println(name+" 喝水,剩下 "+w + " 克");
notify();
try {
Thread.sleep(1000);
wait();
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
if(w==0) System.exit(0);
}
}
} 运行结果:
一共10克水,dog和cat每次喝1克水
dog 喝水,剩下 9 克
Exception in thread "dog" cat 喝水,剩下 8 克
Exception in thread "cat" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at test1.run(test1.java:29)
at java.lang.Thread.run(Unknown Source)
java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at test1.run(test1.java:16)
at java.lang.Thread.run(Unknown Source)

## 书本上面没有使用synchronized

/**
* @author nienie
*
*/ public class Example12_2 { /**
* @param args
*/
public static void main(String[] args) {
// TODO 自动生成的方法存根
House house = new House();
house.serWater(10);
Thread dog,cat;
dog = new Thread(house);
cat = new Thread(house);
dog.setName("dog");
cat.setName("cat");
dog.start();
cat.start();
} }
public class House implements Runnable{
int waterAmount;
public void serWater(int w){
waterAmount = w;
}
public void run() {
int m = 1;
while(true){
if(waterAmount <=0){
return;
}
waterAmount = waterAmount -m;
System.out.println("剩 "+waterAmount+" 克");
try{
Thread.sleep(2000);
}
catch (Exception e) {}
}
}
}
运行结果:
剩 9 克
剩 8 克
剩 7 克
剩 7 克
剩 6 克
剩 6 克
剩 5 克
剩 5 克
剩 4 克
剩 4 克
剩 3 克
剩 3 克
剩 2 克
剩 2 克
剩 0 克
剩 0 克

明显的出现了很多重复的,所以这里就要用到synchronized

书本上使用synchronized的另外一个例子

/**
* @author nienie
*
*/ public class Example12_5 { /**
* @param args
*/
public static void main(String[] args) {
// TODO 自动生成的方法存根
Bank bank = new Bank();
bank.setMoney(200);
Thread accountant,cashier;
accountant = new Thread(bank);
cashier = new Thread(bank);
accountant.setName("会计");
cashier.setName("出纳");
accountant.start();
cashier.start();
}
} public class Bank implements Runnable{
int money = 200;
public void setMoney(int n){
money = n;
}
public void run() {
// TODO 自动生成的方法存根
if(Thread.currentThread().getName().equals("会计"))
saveOtTake(300);
else if(Thread.currentThread().getName().equals("出纳"))
saveOtTake(150);
}
public synchronized void saveOtTake(int amount) {
// TODO 自动生成的方法存根
if(Thread.currentThread().getName().equals("会计")){
for (int i=1;i<3;i++){
money = money + amount/3;
System.out.println(Thread.currentThread().getName()+" 存入 "+amount/3+" ,账上有 "+money+" 万,休息一会再存");
try{
Thread.sleep(1000);
}
catch (InterruptedException e) {}
}
}
else if(Thread.currentThread().getName().equals("出纳")){
for (int i=1;i<3;i++){
money = money - amount/3;
System.out.println(Thread.currentThread().getName()+" 取出 "+amount/3+" ,账上有 "+money+" 万,休息一会再取");
try{
Thread.sleep(1000);
}
catch (InterruptedException e) {}
}
}
}
} 运行结果:
会计 存入 100 ,账上有 300 万,休息一会再存
会计 存入 100 ,账上有 400 万,休息一会再存
会计 存入 100 ,账上有 500 万,休息一会再存
出纳 取出 50 ,账上有 450 万,休息一会再取
出纳 取出 50 ,账上有 400 万,休息一会再取
出纳 取出 50 ,账上有 350 万,休息一会再取

这里也是共用一个资源,但是有一个问题就是,这里的是要会计一直工作完,然后出纳才可以做,就是无论里面有多少钱,只要会计还没有将钱存完,出纳就无法拿钱,哪怕里面的钱足够,这样子就起不到两个线程交替运行了,所以这里还要修改一下,使会计和出纳交替运行,只要里面够钱,那出纳就可以用,然后拿了之后,会计继续存钱(就是在会计休息的时候,出纳可以拿钱,出纳休息的时候,会计也可以存钱,然后对那个money也有一个锁,不会出现资源混乱。)

对Bank Class进行修改

public synchronized void saveOtTake(int amount) {
// TODO 自动生成的方法存根
if(Thread.currentThread().getName().equals("会计")){
for (int i=1;i<=3;i++){
money = money + amount/3;
System.out.println(Thread.currentThread().getName()+" 存入 "+amount/3+" ,账上有 "+money+" 万,休息一会再存");
notify();
try{
Thread.sleep(1000);
wait();
}
catch (InterruptedException e) {}
}
}
else if(Thread.currentThread().getName().equals("出纳")){
for (int i=1;i<=3;i++){
money = money - amount/3;
System.out.println(Thread.currentThread().getName()+" 取出 "+amount/3+" ,账上有 "+money+" 万,休息一会再取");
notify();
try{
Thread.sleep(1000);
wait();
}
catch (InterruptedException e) {}
}
}
System.exit(0);
}
运行结果:
会计 存入 100 ,账上有 300 万,休息一会再存
出纳 取出 50 ,账上有 250 万,休息一会再取
会计 存入 100 ,账上有 350 万,休息一会再存
出纳 取出 50 ,账上有 300 万,休息一会再取
会计 存入 100 ,账上有 400 万,休息一会再存
出纳 取出 50 ,账上有 350 万,休息一会再取

对java的Thread的理解的更多相关文章

  1. Java线程Thread的状态解析以及状态转换分析 多线程中篇(七)

    线程与操作系统中线程(进程)的概念同根同源,尽管千差万别. 操作系统中有状态以及状态的切换,Java线程中照样也有. State 在Thread类中有内部类 枚举State,用于抽象描述Java线程的 ...

  2. 转载:java中Thread.sleep()函数使用

    点我跳过黑哥的卑鄙广告行为,进入正文. Java多线程系列更新中~ 正式篇: Java多线程(一) 什么是线程 Java多线程(二)关于多线程的CPU密集型和IO密集型这件事 Java多线程(三)如何 ...

  3. Java类加载机制的理解

    算上大学,尽管接触Java已经有4年时间并对基本的API算得上熟练应用,但是依旧觉得自己对于Java的特性依然是一知半解.要成为优秀的Java开发人员,需要深入了解Java平台的工作方式,其中类加载机 ...

  4. 沉淀再出发:关于java中的AQS理解

    沉淀再出发:关于java中的AQS理解 一.前言 在java中有很多锁结构都继承自AQS(AbstractQueuedSynchronizer)这个抽象类如果我们仔细了解可以发现AQS的作用是非常大的 ...

  5. 多线程系列之 java多线程的个人理解(二)

    前言:上一篇多线程系列之 java多线程的个人理解(一) 讲到了线程.进程.多线程的基本概念,以及多线程在java中的基本实现方式,本篇主要接着上一篇继续讲述多线程在实际项目中的应用以及遇到的诸多问题 ...

  6. Java 内省(Introspector)深入理解

    Java 内省(Introspector)深入理解 一些概念: 内省(Introspector) 是Java 语言对 JavaBean 类属性.事件的一种缺省处理方法. JavaBean是一种特殊的类 ...

  7. Java并发--Thread类详情

    以下是本文的目录大纲: 一.线程的状态 二.上下文切换 三.Thread类中的方法 转载原文链接:http://www.cnblogs.com/dolphin0520/p/3920357.html 一 ...

  8. java.lang.Thread类详解

    java.lang.Thread类详解 一.前言 位于java.lang包下的Thread类是非常重要的线程类,它实现了Runnable接口,今天我们来学习一下Thread类,在学习Thread类之前 ...

  9. java之结合代码理解synchronized关键字

    为了保证数据的一致性即实现线程的安全性,java虚拟机提供了同步和锁机制.synchronized关键字是最基本的互斥同步手段.除此之外,还可以使用java.util.concurrent包中的重入锁 ...

随机推荐

  1. Nginx:413 Request Entity Too Large解决

    最近在做给博客添加上传PDF的功能,但是在测试上传文件的过程中遇到了413 Request Entity Too Large错误.不过这个无错误是很好解决的,这个错误的出现是因为上传的文件大小超过了N ...

  2. Jenkins实现PHP的自动部署

    1.汉化jenkins 1).安装汉化包 系统管理 -> 插件管理 -> 安装插件 ->选择插件(Locale plugin) 2).设置语言为中文 系统管理 -> 系统设置 ...

  3. Mybatis使用总结-思维导图

    目前使用到Mybatis的总结,缓存还未涉及:

  4. 一步一步从原理跟我学邮件收取及发送 13.mime格式与常见字符编码

    在前面的本系列文章中我们已经学会了邮件的发送和收取.但在收取中我们看到的是一串串的乱码,回忆前面的发送过程,我们会奇怪:我们前面的邮件是明文啊.为什么明文的邮件明明也可以正常工作,还要弄乱码似的字符串 ...

  5. Linux-PATH_环境变量

    PATH变量         是linux系统里的一个环境变量,系统已经定义好了,我们不需要再定义. 作用:         是linux里使用的命令都存在在PATH变量后面指定的目录下,我们使用命令 ...

  6. vim学习、各类插件配置与安装

    vim学习.各类插件配置与安装 vim 插件 配置 1. vim学习 vim基础学习:根据网上流行基础文章<简明Vim练级攻略>,进阶书籍<vim实用技巧>.注:进阶书籍可以在 ...

  7. SQL替换语句 批量修改、增加、删除字段内容

    sql替换语句,用该命令可以整批替换某字段的内容,也可以批量在原字段内容上加上或去掉字符. 命令总解:update 表的名称 set 此表要替换的字段名=REPLACE(此表要替换的字段名, '原来内 ...

  8. MIPS中有关于分支指令及跳转寻址

    分支指令 分支指令包含该指令,和两个操作数,以及跳转的分支地址,该地址是相对于下一条指令的相对地址 分支指令占6位   操作数1占5位     操作数2占5位     分支指令16位 例如 bne  ...

  9. 通过 Service 访问 Pod - 每天5分钟玩转 Docker 容器技术(136)

    本节开始学习 Service.我们不应该期望 Kubernetes Pod 是健壮的,而是要假设 Pod 中的容器很可能因为各种原因发生故障而死掉.Deployment 等 controller 会通 ...

  10. MYSQL索引的类型和索引的方式

    索引的类型: normal:表示普通索引 unique:表示唯一的,不允许重复的索引,如果该字段信息保证不会重复例如身份证号用作索引时,可设置为unique full textl: 表示 全文搜索的索 ...