补充:

线程的创建方式二:

  1.自定义一个实现Runnable接口的类

  2.实现Runnable接口中的run方法把自定义线程的任务写在run方法中

  3.创建实现Runnable接口的对象

  4.创建Thread类的对象,并且把 3 中的对象作为实参传递(Thread thread = new Thread(Runnable target,"名字");)

  5.调用Thread对象的start方法,开启一个线程

课后习题:一个银行账户5000块,两夫妻一个拿着 存折,一个拿着卡,开始取钱比赛,每次只能取100块,要求不准出现线程安全问题。用线程创建方法二实现。

public class Demo1 implements Runnable {

    static int money = 5000;
static Object lock = new Object(); public Demo1(String string) { } public void run() {
while(true) {
synchronized (lock) {
if(money>0) {
System.out.println(Thread.currentThread().getName()+"取走100元,还剩"+(money-100)+"元!");
money-=100;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else {
System.out.println("银行卡没有存款了!");
break;
}
}
}
} public static void main(String[] args) {
Demo1 men = new Demo1("男士");
Demo1 women = new Demo1("女士"); Thread a = new Thread(men,"男士");
Thread b = new Thread(men,"女士"); a.start();
b.start();
} }

Q:为什么要把实现Runnable接口的类的对象作为实参传给Thread对象?作用是什么?

A:作用是把实现Runnable接口的类的对象的run方法作为线程的任务代码去执行,也就是把实现Runnable接口的类的对象的作为任务代码传给Thread对象的run方法执行。

线程安全性问题解决方法

方式二:同步函数  :  同步函数就是使用synchronized修饰一个函数。(大多数情况锁不住)

同步函数要注意的事项 : 同步函数的锁对象是固定的,不能由你来指定的。

优先使用: 同步代码块。
               1. 同步代码块的锁对象可以由我们随意指定,方便控制。同步函数的锁对象是固定 的,不能由我们来指定。
              2. 同步代码块可以很方便控制需要被同步代码的范围,同步函数必须是整个函数 的所有代码都被同步了。

新内容:

死锁

java中同步机制解决了线程安全问题,但是也同时引发死锁现象。

死锁现象出现的原因:

1. 存在两个或者两个以上的线程。
 2. 存在两个或者两个以上的共享资源。
 
解决方案: 没有方案。只能避免发生。

//演示代码(摘录):
class DeadLock extends Thread{ public DeadLock(String name){
super(name);
} public void run() {
if("张三".equals(Thread.currentThread().getName())){
synchronized ("遥控器") {
System.out.println("张三拿到了遥控器,准备 去拿电池!!");
synchronized ("电池") {
System.out.println("张三拿到了遥控器与电池了,开着空调爽歪歪的吹着...");
}
}
}else if("狗娃".equals(Thread.currentThread().getName())){
synchronized ("电池") {
System.out.println("狗娃拿到了电池,准备去拿遥控器!!");
synchronized ("遥控器") {
System.out.println("狗娃拿到了遥控器与电池了,开着空调爽歪歪的吹着...");
}
}
}
}
} public class Demo2 {
public static void main(String[] args) {
DeadLock thread1 = new DeadLock("张三");
DeadLock thread2 = new DeadLock("狗娃");
//开启线程
thread1.start();
thread2.start();
}
}

分析:此时开启了两个线程

当 thread1主动调用run方法在分支结构判断为真的时候获得遥控器资源后(synchronized ("遥控器") 状态为关闭), thread2已经获得了分支结构中下一个的电池资源,但由于遥控器锁和电池锁是共享资源,所以两个线程互相等待对方解锁才能获得资源,然后才能解锁状态,但是两个资源的锁状态一直为关闭又无法进入,所以进入了死锁状态。

线程的通信

线程通讯:一个线程完成了自己的任务时,要通知另外一个线程去完成另外一个任务.

wait():  等待   如果线程执行了wait方法,那么该线程会进入等待的状态,等待状态下的线程必须要被其他线程调用notify方法才能唤醒。

notify(): 唤醒    唤醒线程池等待线程其中的一个。
notifyAll() : 唤醒线程池所有等待 线程。

wait与notify方法要注意的事项:
 1. wait方法与notify方法是属于Object对象 的。
 2. wait方法与notify方法必须要在同步代码块或者是同步函数中才能 使用。
 3. wait方法与notify方法必需要由锁对象调用。

作业:有一个水池,水池的容量是固定 的500L,一边为进水口,一边为出水口.要求,进水与放水不能同时进行.水池一旦满了不能继续注水,一旦放空了,不可以继续放水. 进水的速度5L/s ,  放水的速度2L/s 

class watercave{

    String name;
int Sumwater = 0;
boolean flag = false; } class in extends Thread{
watercave p; public in(watercave p) {
this.p = p;
} public void run() {
while(true) {
synchronized (p) {
if(p.flag==false) {
if(p.Sumwater<500) {
p.Sumwater+=5;
System.out.println("现在有 "+p.Sumwater+"L 水!");
p.flag=true;
p.notify();
}
}else {
try {
p.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
} class out extends Thread{
watercave p; public out(watercave p) {
this.p = p;
} public void run() {
while(true) {
synchronized (p) {
if(p.flag==true) {
if(p.Sumwater>0) {
p.Sumwater-=2;
System.out.println("还剩"+p.Sumwater+"L 水!");
p.flag=false;
p.notify();
}
}
else {
try {
p.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} }
}
} public class Demo2 {
public static void main(String[] args) {
watercave p = new watercave(); in a = new in(p);
out b= new out(p); a.start();
b.start();
}
}

线程的停止

1. 停止一个线程 我们一般都会通过一个变量去控制的。
2. 如果需要停止一个处于等待状态下的线程,那么我们需要通过变量配合notify方法或者interrupt()来使用

//引用代码并分析
public class Demo6 extends Thread { boolean flag = true; public Demo6(String name){
super(name);
}
public synchronized void run() {
int i = 0 ;
while(flag){
try {
this.wait(); //狗娃等待.. } catch (InterruptedException e) {
System.out.println("接收到了异常了....");
}
System.out.println(Thread.currentThread().getName()+":"+i);
i++;
}
} public static void main(String[] args) {
Demo6 d = new Demo6("狗娃");
d.setPriority(10);
d.start(); for(int i = 0 ; i<100 ; i++){
System.out.println(Thread.currentThread().getName()+":"+i);
//当主线程的i是80的时候停止狗娃线程。
//d.interrupt(); // interrupt()根本就是无法停止一个线程。
if(i==80){
d.flag = false;
d.interrupt(); //把线程的等待状态强制清除,被清除状态的线程会接收到一个InterruptedException。
/*synchronized (d) {
d.notify();
}*/
}
}
}
}

当代码中启动两个线程的时候要用synchronized将狗娃线程的执行代码给锁定,这样才不会出现线程争夺资源所出现的,无法停止一个线程的现象。

后台线程 

后台线程(守护线程):在一个进程中如果只剩下 了守护线程,那么守护线程也会死亡。

Q:如何判断线程是不是守护线程?

A:首先线程默认都不是守护线程,需要设置(*.setDaemon(true);true表示设置为守护线程,false表示设置为不是守护线程)。

判断方法(.isDaemon();返回值为true就是守护线程,返回值为false就不是守护线程)

?:模拟QQ下载更新包

public class Demo3 extends Thread {

    public Demo3(String name){
super(name);
} public void run() {
for(int i = 1 ; i<=100 ; i++){
System.out.println("更新包目前下载"+i+"%");
if(i==100){
System.out.println("更新包下载完毕,准备安装..");
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static void main(String[] args) {
Demo3 d = new Demo3("后台线程");
d.setDaemon(true);
d.start();
for(int i = 1 ; i<=100 ; i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}

效果图

join方法:一个线程如果执行了join语句,那么就有新的线程加入,执行该语句的线程必须让步给新加入的线程完成任务,然后才能继续执行任务。

//使用方法
class Mon extends Thread{
public void run() {
System.out.println("妈妈洗菜");
System.out.println("妈妈切菜");
System.out.println("妈妈准备炒菜,发现没有酱油了..");
//叫儿子去打酱油
Son s= new Son();
s.start();
try {
s.join();
} catch (InterruptedException e) {
e.printStackTrace();
} System.out.println("妈妈继续炒菜");
System.out.println("全家一起吃饭..");
}
} class Son extends Thread{ public void run() {
System.out.println("儿子下楼..");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("儿子一直往前走");
System.out.println("儿子打完酱油了");
System.out.println("上楼,把酱油给老妈");
}
} public class Demo8 { public static void main(String[] args) {
Mon m = new Mon();
m.start(); }
}

进程与线程篇终结

Day 2:线程与进程系列问题(二)的更多相关文章

  1. Day 1:线程与进程系列问题(一)

    一.进程与线程 进程:正在执行的程序称为一个线程,主要负责内存空间的划分. 线程:线程在一个进程中负责代码的执行,就是进程中的一个执行路径. 多线程:在一个进程中有多个线程同时在执行不同的任务(同时指 ...

  2. C#多线程编程系列(二)- 线程基础

    目录 C#多线程编程系列(二)- 线程基础 1.1 简介 1.2 创建线程 1.3 暂停线程 1.4 线程等待 1.5 终止线程 1.6 检测线程状态 1.7 线程优先级 1.8 前台线程和后台线程 ...

  3. Java Thread系列(二)线程状态

    Java Thread系列(二)线程状态 一.线程的五种状态 新建状态(New):新创建了一个线程对象,尚未启动. 就绪状态(Runnable):也叫可运行状态.线程对象创建后,其他线程调用了该对象的 ...

  4. 2015年11月25 Java基础系列(二)Thread Runnable线程初级讲解

    序,线程是比进程小的进程,非常广泛的被使用. 一.继承Thread实现线程操作 1.注意setDaemon(boolean)方法,参数为true时为守护线程,参数为false时为用户线程. 守护线程的 ...

  5. {Python之线程} 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Threading模块 九 锁 十 信号量 十一 事件Event 十二 条件Condition(了解) 十三 定时器

    Python之线程 线程 本节目录 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Thr ...

  6. Py修行路 python基础 (二十五)线程与进程

    操作系统是用户和硬件沟通的桥梁 操作系统,位于底层硬件与应用软件之间的一层 工作方式:向下管理硬件,向上提供接口 操作系统进行切换操作: 把CPU的使用权切换给不同的进程. 1.出现IO操作 2.固定 ...

  7. 进程与线程 .Net Core系列-多线程

    进程与线程 进程: 狭义定义:进程是正在运行的程序的实例 广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动.它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分 ...

  8. Sql Server来龙去脉系列之二 框架和配置

    本节主要讲维持数据的元数据,以及数据库框架结构.内存管理.系统配置等.这些技术点在我们使用数据库时很少接触到,但如果要深入学习Sql Server这一章节也是不得不看.本人能力有限不能把所有核心的知识 ...

  9. JVM 系列(二)内存模型

    02 JVM 系列(二)内存模型 一.JVM 内存区域 JVM 会将 Java 进程所管理的内存划分为若干不同的数据区域.这些区域有各自的用途.创建/销毁时间: 一. 线程私有区域 线程私有数据区域生 ...

随机推荐

  1. 2018--Linux面试题

    1.企业场景面试题:buffer与Cache的区别. 2.企业场景面试题:redhat与CentOS的区别. 3.企业场景面试题:  描述RAID 0 1 5 10的特点. 4.企业场景面试题:32位 ...

  2. 配置uboot指定nfs挂载根文件系统

    背景: 文件系统的调试也建议在 网络中进行. 概念: NFS是Network File System的缩写及网络文件系统. 要功能是通过局域网络让不同的主机系统之间可以共享文件或目录. NFS系统和W ...

  3. volume 方式使用 Secret【转】

    Pod 可以通过 Volume 或者环境变量的方式使用 Secret,今天先学习 Volume 方式. Pod 的配置文件如下所示: ① 定义 volume foo,来源为 secret mysecr ...

  4. 当3D打影人头”成为黑客的秘密武器,隐私该如何保护?

    在<碟中谍>系列电影中,除了超级敬业又帅气的阿汤哥之外,最让人津津乐道的桥段就是用3D打印做出来的"人头".通过这些惟妙惟肖的"人头",阿汤哥完成了 ...

  5. STM32+Nokia5110LCD

    Nokia5110LCD(84*48) lcd.h #ifndef _LCD_H#define _LCD_H #include "sys.h" #include "std ...

  6. 【LeetCode】三角形最小路径和

    [问题]给定一个三角形,找出自顶向下的最小路径和.每一步只能移动到下一行中相邻的结点上.例如,给定三角形: [ [], [,], [,,], [,,,] ] 自顶向下的最小路径和为 (即, + + + ...

  7. qq群的表设计探究

    2018年3月21日  课题组管理就如qq的群是一样的,课题组有课题组组长:qq群有群主:课题组有组员:qq群有群人员 对于一个课题组来说,组长可以对课题组进行修改,组员只能看得见,但是不能修改.所以 ...

  8. Golang的基础数据类型-字符串型

    Golang的基础数据类型-字符串型 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.字符型概述 上一篇博客学习了使用单引号括起来的单个字符就是字符类型,在Golang中有两种表 ...

  9. SSM整合搭建过程中的一个怪异问题

    好久没有搭建框架了,昨天开始试图搭建一个SSM框架,各种配置文件搭建成功,服务器也启动正确,但是在运行过程中,发现总是不能获取JDBC,不能够创建连接池工厂,报错如下:网页报500错误码 SEVERE ...

  10. 【java】【反射】反射实现判断发生了修改操作,判断两个对象是否发生属性值的变更,判断两个List集合内对象的属性值是否发生变更

    java的反射实现: 判断发生了修改操作,判断两个对象是否发生属性值的变更,判断两个List集合内对象的属性值是否发生变更 今日份代码: package com.sxd.streamTest; imp ...