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. 使用vue+ivew做2048小游戏

    首先先弄页面 废话不多说 上代码 静态页面代码 <template> <div class="main"> <div class="top& ...

  2. 5.Django cookie

    概述 1.获取cookie request.COOKIES['key'] request.COOKIES.get('key') request.get_signed_cookie(key, defau ...

  3. Python爬虫入门教程 30-100 高考派大学数据抓取 scrapy

    1. 高考派大学数据----写在前面 终于写到了scrapy爬虫框架了,这个框架可以说是python爬虫框架里面出镜率最高的一个了,我们接下来重点研究一下它的使用规则. 安装过程自己百度一下,就能找到 ...

  4. Java基础17:Java IO流总结

    更多内容请关注微信公众号[Java技术江湖] 这是一位阿里 Java 工程师的技术小站,作者黄小斜,专注 Java 相关技术:SSM.SpringBoot.MySQL.分布式.中间件.集群.Linux ...

  5. 【c#】RabbitMQ学习文档(六)RPC(远程调用)

    远程过程调用(Remote Proceddure call[RPC]) (本实例都是使用的Net的客户端,使用C#编写) 在第二个教程中,我们学习了如何使用工作队列在多个工作实例之间分配耗时的任务. ...

  6. Hibernate【inverse和cascade属性】知识要点

    Inverse属性 Inverse属性:表示控制权是否转移.. true:控制权已转移[当前一方没有控制权] false:控制权没有转移[当前一方有控制权] Inverse属性,是在维护关联关系的时候 ...

  7. Android总结篇系列:Activity启动模式(lauchMode)

    本来想针对Activity中的启动模式写篇文章的,后来网上发现有人已经总结的相当好了,在此直接引用过来,并加上自己的一些理解,在此感谢原作者. 文章地址: http://blog.csdn.net/l ...

  8. javaWeb项目中的路径格式 请求url地址 客户端路径 服务端路径 url-pattern 路径 获取资源路径 地址 url

    javaweb项目中有很多场景的路径客户端的POST/GET请求,服务器的请求转发,资源获取需要设置路径等这些路径表达的含义都有不同,所以想要更好的书写规范有用的路径代码 需要对路径有一个清晰地认知 ...

  9. Powershell:关于hashtable你想知道的一切

    译者语:本篇为一篇译文,详细介绍了在powershell中如何使用hashtable这种数据类型.本文为本人2018年最后一篇博文(哈哈,一年内写没写几篇),也是本人的第一次译文,有不足之处还请指教. ...

  10. .Net语言 APP开发平台——Smobiler学习日志:在手机应用中开发蛛网表格

    最前面的话:Smobiler是一个在VS环境中使用.Net语言来开发APP的开发平台,也许比Xamarin更方便 样式一 一.目标样式 我们要实现上图中的效果,需要如下的操作: 1.从工具栏上的”Sm ...