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多线程基础(二)的更多相关文章

  1. java多线程基础(二)--java多线程的基本使用

    java多线程的基本使用 在java中使用多线程,是通过继承Thread这个类或者实现Runnable这个接口或者实现Callable接口来完成多线程的. 下面是很简单的例子代码: package c ...

  2. Java多线程基础(二)

    信号量Semaphore,类似于锁的功能,用于多线程中对一组资源的控制. acquire方法用于尝试获取一个资源,未获取前将一直等待.release用于释放一个资源,release的前提是已经获得了一 ...

  3. Java 多线程基础(十二)生产者与消费者

    Java 多线程基础(十二)生产者与消费者 一.生产者与消费者模型 生产者与消费者问题是个非常典型的多线程问题,涉及到的对象包括“生产者”.“消费者”.“仓库”和“产品”.他们之间的关系如下: ①.生 ...

  4. [转]Java多线程干货系列—(一)Java多线程基础

    Java多线程干货系列—(一)Java多线程基础 字数7618 阅读1875 评论21 喜欢86 前言 多线程并发编程是Java编程中重要的一块内容,也是面试重点覆盖区域,所以学好多线程并发编程对我们 ...

  5. Java多线程基础:进程和线程之由来

    转载: Java多线程基础:进程和线程之由来 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程.当然,Java并发编程涉及到很多方面的内容,不是一朝一夕就能够 ...

  6. Java 多线程——基础知识

    java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...

  7. Java多线程(二)关于多线程的CPU密集型和IO密集型这件事

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

  8. 1、Java多线程基础:进程和线程之由来

    Java多线程基础:进程和线程之由来 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程.当然,Java并发编程涉及到很多方面的内容,不是一朝一夕就能够融会贯通 ...

  9. Java 多线程基础(一)基本概念

    Java 多线程基础(一)基本概念 一.并发与并行 1.并发:指两个或多个事件在同一个时间段内发生. 2.并行:指两个或多个事件在同一时刻发生(同时发生). 在操作系统中,安装了多个程序,并发指的是在 ...

  10. Java 多线程基础(三) start() 和 run()

    Java 多线程基础(三) start() 和 run() 通过之前的学习可以看到,创建多线程过程中,最常用的便是 Thread 类中的 start() 方法和线程类的 run() 方法.两个方法都包 ...

随机推荐

  1. Docker系列教程01-Centos7安装新版Docker教程(10步)

    最近一直忙于开发,没有时间好好总结一下docker的知识.其实现在docker的教程已经很多很多了,但是很多系统的教程都是基于Ubuntu系统,因为官方推荐使用Ubuntu系统啊,原因在于Ubuntu ...

  2. 【Spark篇】---SparkSQL on Hive的配置和使用

    一.前述 Spark on Hive: Hive只作为储存角色,Spark负责sql解析优化,执行. 二.具体配置 1.在Spark客户端配置Hive On Spark 在Spark客户端安装包下sp ...

  3. Pycharm使用教程(三)(非常详细,非常实用)

    1. 汉化:把resources_zh.jar拷贝到PyCharm的安装目录下的lib目录,重启Pycharm即可. (resources_zh.jar汉化包关注本账号获取:链接: https://p ...

  4. 深入解析 H.265 编码模式,带你了解Apple全面推进H.265的原因

    今天我们聊聊视频编码.视频文件亘古以来存在一个矛盾:高清画质和视频体积的冲突,相同编码标准下,视频更高清,视频体积更大.因此,应用更先进的视频编码标准,降低视频体积,可以大幅降低网站的流量消耗. 目前 ...

  5. Entitiy Framework Core中使用ChangeTracker持久化实体修改历史

    背景介绍 在我们的日常开发中,有时候需要记录数据库表中值的变化, 这时候我们通常会使用触发器或者使用关系型数据库中临时表(Temporal Table)或数据变更捕获(Change Data Capt ...

  6. 带着新人学springboot的应用05(springboot+RabbitMQ 上)

    这次就来说说RabbitMQ,这个应该不陌生了,随便一查就知道这个是用来做消息队列的.(注意:这一节很多都是概念的东西,需要操作的比较少) 至于AMQP协议(Advanced Message Queu ...

  7. Chapter 5 Blood Type——7

    "You say that a lot," I noted, trying to ignore the sudden trembling in my stomach and kee ...

  8. 【ASP.NET Core快速入门】(十四)MVC开发:UI、 EF + Identity实现、注册实现、登陆实现

    前言 之前我们进行了MVC的web页面的Cookie-based认证实现,接下来的开发我们要基于之前的MvcCookieAuthSample项目做修改. MvcCookieAuthSample项目地址 ...

  9. Linux 进程管理工具 supervisord 安装及使用

    Supervisor是用Python实现的一款非常实用的进程管理工具 1.安装过程非常简单 安装python 安装meld3-0.6.8.tar.gz 安装supervisor-3.0a12.tar. ...

  10. JavaScript的事件及异常捕获

    事件处理 [onClick]单击事件.[onMouseOver]鼠标经过事件.[onMouseOut]鼠标移出事件.[onChange]文本内容改变事件.[onSelect]文本被框选事件.[onFo ...