Java多线程基础(二)
1.多线程数据安全
线程同步:多个线程需要访问同一资源时,需要以某种顺序来确定该资源某一时刻只能被一个线程使用。从而,解决并发操作可能带来的异常。
2.同步代码块实现同步(部分代码的访问,我们希望它同步)
synchronized(lock){
//同步代码块
}
其中lock就是同步监视器,它的含义是:线程开始执行同步代码块之前,必须先获得对同步监视器的锁定。任何时刻只能有一个线程可以获得对同步监视器的锁定,当同步代码块执行完成后,该线程会释放对该同步监视器的锁定。虽然java程序允许使用任何对象作为同步监视器,但是同步监视器的目的就是为了阻止两个线程对同一个共享资源进行并发访问,因此通常使用可能被并发访问的共享资源充当同步监视器。
下面的实例可方便理解:
package com.test; public class ThreadDemo1 { public static void main(String[] args) {
// TODO Auto-generated method stub
//创建共享资源对象
TicketRes ticketRes=new TicketRes();
//创建线程对象
Thread w1=new Thread(ticketRes,"窗口1");
Thread w2=new Thread(ticketRes,"窗口2");
Thread w3=new Thread(ticketRes,"窗口3");
w1.start();
w2.start();
w3.start();
}
}
//共享资源类
class TicketRes implements Runnable{
private int ticket=100;
private Object lock=new Object();//锁 @Override
public void run() {
// TODO Auto-generated method stub
while(true) {
synchronized (lock) {
if(ticket>=1) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖第"+ticket+"张票");
ticket--;
}else {
break;
}
}
}
}
}
3.同步方法实现同步(强调功能,方法的访问是同步的)
同步方法就是使用synchronized关键字修饰某个方法,用synchronized修饰的方法就是同步方法。这个同步方法(非static方法)无须显式指定同步监视器,同步方法的同步监视器是this,也就是调用该方法的对象,通过同步方法可以非常方便的实现线程安全的类。
下面的实例可方便理解:
package com.test; public class ThreadDemo2 { public static void main(String[] args) {
// TODO Auto-generated method stub
//创建共享资源对象
TicketRes1 ticketRes=new TicketRes1();
//创建线程对象
Thread w1=new Thread(ticketRes,"窗口1");
Thread w2=new Thread(ticketRes,"窗口2");
Thread w3=new Thread(ticketRes,"窗口3");
w1.start();
w2.start();
w3.start();
}
}
//共享资源类
class TicketRes1 implements Runnable{
private static int ticket=100;
private Object lock=new Object();//锁 @Override
public void run() {
// TODO Auto-generated method stub
while(true) {
if(!TicketRes1.saleTicket()) {
break;
}
}
}
public synchronized static boolean saleTicket() {
if(ticket>=1) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖第"+ticket+"张票");
ticket--;
return true;
}else {
return false;
}
}
}
4.锁的概念以及死锁问题
多线程在运行的时候可能会遇到这样的问题,多个线程要用到同一个资源,那可能会出现错乱,比如线程要改动资源里的数据,那么多个线程同时改就乱了套了。就像公共厕所,必须要一个一个接着上,不能两个人或者多个人同时上。那么锁这个概念就是像上厕所的门,一个人在上厕所,锁上了门,那下一个人就不能进去了。同样的,如果我们想让某一个程序或者某一个变量只能同时被一个线程运行,就得给程序上锁。所以上了锁,就能保证线程有秩序地运行。
当两个线程相互等待对方释放同步监视器时就会发生死锁,Java虚拟机没有检测,也没有采取措施来处理死锁情况,所以多线程编程时应该采取措施避免死锁出现。一旦出现死锁,程序既不会发生任何异常,也不会给出任何提示,只是所有线程都处于阻塞状态,无法继续。
接下来看一个死锁的Java实例(是不是停不下来了,就相当于循环语句的死循环)
package com.test; public class DeadLock { public static void main(String[] args) {
// TODO Auto-generated method stub
DeadLockThread he=new DeadLockThread(true,"小明");//他
DeadLockThread she=new DeadLockThread(false,"小华 ");//她
he.start();
she.start();
}
}
//线程
class DeadLockThread extends Thread{
boolean flag=false;
public DeadLockThread() { }
protected DeadLockThread(boolean flag,String name) {
super(name);
this.flag=flag;
}
public void run() {
while(true) {
if(flag) {
synchronized (Lock.locka) {//他
System.out.println(Thread.currentThread().getName()+"抢到了locka");
}
synchronized (Lock.lockb) {
System.out.println(Thread.currentThread().getName()+"抢到了lockb");
System.out.println(Thread.currentThread().getName()+"可以上厕所了"); }
}else {
synchronized (Lock.lockb) {//她
System.out.println(Thread.currentThread().getName()+"抢到了lockb");
}
synchronized (Lock.locka) {
System.out.println(Thread.currentThread().getName()+"抢到了locka");
System.out.println(Thread.currentThread().getName()+"可以上厕所了");
}
}
}
}
}
//创建锁对象
class Lock{
public static Object locka=new Object();
public static Object lockb=new Object();
}
5.线程终止
1.使用标志,使run()方法正常执行完毕
package com.test; import java.util.Scanner; public class Demo1 { public static void main(String[] args) {
// TODO Auto-generated method stub
FlagStop flagStop=new FlagStop("线程1");
flagStop.start();
Scanner input=new Scanner(System.in);
System.out.println("输入任意字符结束主线程");
input.next();
flagStop.flag=false;//主线程修改其他线程的变量
System.out.println("主线程结束");
} }
class FlagStop extends Thread{
//定义标志 volatile:易挥发的、不稳定的,使用volatile修饰后,获取变量不会从缓存中取,从内存中取。
volatile boolean flag=true;
public FlagStop() {
// TODO Auto-generated constructor stub
} public FlagStop(String name) {
super(name);
// TODO Auto-generated constructor stub
} @Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName()+"开始执行了");
while(flag) { }
System.out.println(Thread.currentThread().getName()+"执行完毕");
}
}
2.使用stop方法强制终止线程
package com.test; import java.util.Scanner; public class Demo2 { public static void main(String[] args) {
// TODO Auto-generated method stub
WordStop wordStop=new WordStop("线程1");
wordStop.start();
Scanner input=new Scanner(System.in);
System.out.println("输入任意字符结束主线程");
input.next();
wordStop.stop();
wordStop.flag=false;//主线程修改其他线程的变量
System.out.println("主线程结束");
} }
class WordStop extends Thread{
//定义标志 volatile:易挥发的、不稳定的,使用volatile修饰后,获取变量不会从缓存中取,从内存中取。
volatile boolean flag=true;
public WordStop() {
// TODO Auto-generated constructor stub
} public WordStop(String name) {
super(name);
// TODO Auto-generated constructor stub
} @Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName()+"开始执行了");
while(flag) { }
System.out.println(Thread.currentThread().getName()+"执行完毕");
}
}
3.使用interrupt方法中断线程
package com.test; import java.io.IOException; public class Demo3 { public static void main(String[] args) throws IOException, InterruptedException {
// TODO Auto-generated method stub
InterruptStop interruptStop=new InterruptStop();
interruptStop.start();
System.out.println("在10秒之内输入任意符号结束");
System.in.read();
interruptStop.interrupt();//打断正在休眠的线程
interruptStop.join();
System.out.println("主线程结束...");
}
}
class InterruptStop extends Thread{
@Override
public void run() {
try {
Thread.sleep(10000);//抛出一个异常InterruptedException
} catch (InterruptedException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
System.out.println("执行了catch");
}
System.out.println("子线程执行完毕");
}
}
6.线程间通信
1.wait:挂起当前线程,释放共享资源锁
2.notify:在所有的wait线程当中随机选择一条唤醒
3.notifyAll:唤醒全部wait线程
Java多线程基础(二)的更多相关文章
- java多线程基础(二)--java多线程的基本使用
java多线程的基本使用 在java中使用多线程,是通过继承Thread这个类或者实现Runnable这个接口或者实现Callable接口来完成多线程的. 下面是很简单的例子代码: package c ...
- Java多线程基础(二)
信号量Semaphore,类似于锁的功能,用于多线程中对一组资源的控制. acquire方法用于尝试获取一个资源,未获取前将一直等待.release用于释放一个资源,release的前提是已经获得了一 ...
- Java 多线程基础(十二)生产者与消费者
Java 多线程基础(十二)生产者与消费者 一.生产者与消费者模型 生产者与消费者问题是个非常典型的多线程问题,涉及到的对象包括“生产者”.“消费者”.“仓库”和“产品”.他们之间的关系如下: ①.生 ...
- [转]Java多线程干货系列—(一)Java多线程基础
Java多线程干货系列—(一)Java多线程基础 字数7618 阅读1875 评论21 喜欢86 前言 多线程并发编程是Java编程中重要的一块内容,也是面试重点覆盖区域,所以学好多线程并发编程对我们 ...
- Java多线程基础:进程和线程之由来
转载: Java多线程基础:进程和线程之由来 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程.当然,Java并发编程涉及到很多方面的内容,不是一朝一夕就能够 ...
- Java 多线程——基础知识
java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...
- Java多线程(二)关于多线程的CPU密集型和IO密集型这件事
点我跳过黑哥的卑鄙广告行为,进入正文. Java多线程系列更新中~ 正式篇: Java多线程(一) 什么是线程 Java多线程(二)关于多线程的CPU密集型和IO密集型这件事 Java多线程(三)如何 ...
- 1、Java多线程基础:进程和线程之由来
Java多线程基础:进程和线程之由来 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程.当然,Java并发编程涉及到很多方面的内容,不是一朝一夕就能够融会贯通 ...
- Java 多线程基础(一)基本概念
Java 多线程基础(一)基本概念 一.并发与并行 1.并发:指两个或多个事件在同一个时间段内发生. 2.并行:指两个或多个事件在同一时刻发生(同时发生). 在操作系统中,安装了多个程序,并发指的是在 ...
- Java 多线程基础(三) start() 和 run()
Java 多线程基础(三) start() 和 run() 通过之前的学习可以看到,创建多线程过程中,最常用的便是 Thread 类中的 start() 方法和线程类的 run() 方法.两个方法都包 ...
随机推荐
- MySQL优化之推荐使用规范
一.基础规范 使用InnoDB存储引擎支持事务.行级锁.并发性能更好.CPU及内存缓存页优化使得资源利用率更高 推荐使用utf8mb4字符集无需转码,无乱码风险, 支持emoji表情以及部分不常见汉字 ...
- JVM基础系列第4讲:从源代码到机器码,发生了什么?
在上篇文章我们聊到,无论什么语言写的代码,其到最后都是通过机器码运行的,无一例外.那么对于 Java 语言来说,其从源代码到机器码,这中间到底发生了什么呢?这就是今天我们要聊的. 如下图所示,编译器可 ...
- ionic4+angular6 混合移动开发 capacitor cordova
首先要更新或者安装 ionic cli npm install -g ionic 创建项目 ionic start ionic-angular tabs --type=angular –type=an ...
- 个人玩耍VUE..我的点点滴滴,今天很冷,2度!!!
谢谢博客园,可以记录我的点点滴滴.!!这个小案例的效果图 其中,这篇还是上一篇博客的序章,我们直接看下更新的代码. Cart.Vue <template> <div class=&q ...
- 深入并发包 ConcurrentHashMap 源码解析
以前写过介绍HashMap的文章,文中提到过HashMap在put的时候,插入的元素超过了容量(由负载因子决定)的范围就会触发扩容操作,就是rehash,这个会重新将原数组的内容重新hash到新的扩容 ...
- asp.net core系列 25 EF模型配置(隐藏属性)
一. 隐藏属性概述 隐藏属性也叫影子属性,该属性不是在.net实体类中定义的属性,而是在EFCore模型中为该实体类型定义的属性.这些属性的值和状态完全在变更跟踪器中维护.它有二个功能:(1)当数据库 ...
- Chapter 4 Invitations——12
"I don't know what you mean," I said, my voice guarded. “我不知道你什么意思”我声音谨慎地说道. "It's be ...
- Linux下Tomcat开启查看GC信息
本文收录在Linux运维企业架构实战系列 一.开启GC日志 1.在Tomcat 的安装路径下,找到bin/catalina.sh 加上下面的配置,具体参数,自己配置: [root@centos7 to ...
- ELK 经典用法—企业自定义日志收集切割和mysql模块
本文收录在Linux运维企业架构实战系列 一.收集切割公司自定义的日志 很多公司的日志并不是和服务默认的日志格式一致,因此,就需要我们来进行切割了. 1.需切割的日志示例 2018-02-24 11: ...
- [三] java虚拟机 JVM字节码 指令集 bytecode 操作码 指令分类用法 助记符
说明,本文的目的在于从宏观逻辑上介绍清楚绝大多数的字节码指令的含义以及分类 只要认真阅读本文必然能够对字节码指令集有所了解 如果需要了解清楚每一个指令的具体详尽用法,请参阅虚拟机规范 指令简介 计算机 ...