1.多线程数据安全

  线程同步:多个线程需要访问同一资源时,需要以某种顺序来确定该资源某一时刻只能被一个线程使用。

2.同步代码块实现同步(部分代码的访问,我们希望它同步)

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;
                }
            }
        }
    }
}

View Code

3.同步方法实现同步(强调功能,方法的访问是同步的)

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;
        }
    }
}

View Code

4.锁的概念以及死锁问题

  多线程在运行的时候可能会遇到这样的问题,多个线程要用到同一个资源,那可能会出现错乱,比如线程要改动资源里的数据,那么多个线程同时改就乱了套了。就像公共厕所,必须要一个一个接着上,不能两个人或者多个人同时上。那么锁这个概念就是像上厕所的门,一个人在上厕所,锁上了门,那下一个人就不能进去了。同样的,如果我们想让某一个程序或者某一个变量只能同时被一个线程运行,就得给程序上锁。所以上了锁,就能保证线程有秩序地运行。

  接下来看一个死锁的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(); 
}

View Code

 

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()+"执行完毕");
    }
}

View Code

 

  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()+"执行完毕");
    }
}

View Code

  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("子线程执行完毕");
    }
}

View Code

 

6.线程间通信

  1.wait:挂起当前线程,释放共享资源锁

  2.notify:在所有的wait线程当中随机选择一条唤醒

  3.notifyAll:唤醒全部wait线程

版权声明:本文为loober原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/loober/p/10235234.html