多线程

首先我们来了解一下概念
进程:是一个正在执行的程序,每一个进程执行都有一个顺序,该顺序是一个执行路径,或者叫一个控制单元。
线程:就是进程中的一个独立的控制单元,线程在控制着进程的执行。
一个进程中至少有一个线程。
Java VM 启动的时候会有一个进程java.exe
该进程中至少有一个线程负责java程序的执行,而且这个线程运行的代码存在于main方法中,该线程称之为主线程。
另:其实更细节说明jvm,jvm启动不止一个线程,还有负责垃圾回收机制的线程。
多线程存在的意义:使用线程可以把占据时间长的程序中的任务放到后台去处理;用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度;程序的运行速度可能加快;在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了,在这种情况下可以释放一些珍贵的资源如内存占用等等。
线程的创建方式:
通过对API的查找,java已经提供了对线程这类事务的描述,就是Thread类,
创建线程的第一种方式,继承Thread类
步骤:
1.定义类继承Thread类
2.复写Thread类中的run方法,目的:把自定义要运行多线程的代码写入run方法中
3.调用线程的start方法,该方法的作用:启动线程,调用run方法
为什么要复写run方法?
Thread类用于描述线程,该类就定义了一个功能,用于存储线程要运行的代码,该存储功能就是run方法,也就是说,Thread类中的run方法,用于存储线程要运行的代码
发现每次运行结果都不同,因为多个线程都获取cpu的执行权,cpu执行到谁,谁就运行。
明确一点,在某一时刻,只能有一个程序在运行,多核除外。
cpu在做着快速切换,以达到看上去同时运行的效果。
我们可以形象的把多线程的运行行为看成是互相抢夺cpu的执行权

package first;

public class ThreadTest {
    public static void main(String[] args) {
        ThreadDemo thread=new ThreadDemo();//创建好一个线程
        thread.start();
        //thread.run()//这样也可以运行,但没有多线程的效果,是先后运行的了
        for(int i=0;i<10;i++){
            System.out.println("main Run---->"+i);
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
class ThreadDemo extends Thread{
    public void run() {//复写run方法
        for(int i=0;i<10;i++){
            System.out.println("Thread Run*****"+i);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

线程的五种状态图:
这里写图片描述
冻结状态:又分为睡眠和等待两种状态。
临时状态:调用了start方法后,还在等待cpu来处理启动
冻结状态和临时状态的区别是,是否有执行权。
创建线程的第二种方式:
需求:简单的卖票程序,实现多个窗口同时卖票
1.定义类,实现Runnable借口
2.覆盖Runnable接口中的run方法
:将线程要运行的代码存放在run方法中
3.通过Thread类建立线程对象
4.将Runnable借口的子类对象作为实际参数传递给Thread的构造函数
:为什么要将Runnable借口的子类对象传递给Thread的构造函数?
因为自定义的run方法所属的对象是Runnable借口的子类对象,
所以要让线程去运行指定对象的run方法,就必须明确该run方法所属对象
5.调用Thread类的start方法开启线程并调用Runnable借口子类的run方法

package first;  

class Ticket implements Runnable{ //extends Thread{   
    //如果是静态的话,所有的线程会共享这100张票  
    /*private  static int  ticket =100;*/    
    //如果不是静态的话,每一个线程对象都会创建这个ticket对象,也即每个线程拥有100张票卖。  
    //这时候,如果还是采用继承Thread类的方法就不行了,需要使用实现Runnable接口创建线程  
    private  int  ticket =1000;  
    //定义一个对象,为同步使用,任意      
    Object obj= new Object();     
    public void run() {  
        //在这里声明的对象是无效的  
        /*Object obj= new Object(); */  
        while(true){  
            synchronized (obj) {  
                if(ticket>0){      
                    try {  
                        Thread.sleep(10);  

                    } catch (InterruptedException e) {  

                        e.printStackTrace();  
                    }  
                    System.out.println(Thread.currentThread().getName()+".....sale : "+ ticket--);  
                }  
            }  
        }  
    }   
}  
public class TicketDemo {  
    public static void main(String[] args) {  
        Ticket t = new Ticket();  

        Thread t1 = new Thread(t);  
        Thread t2 = new Thread(t);  
        Thread t3 = new Thread(t);  
        Thread t4 = new Thread(t);  

        t1.start();  
        t2.start();  
        t3.start();  
        t4.start();       
    }  
}  

实现 方式和继承方式的区别:
实现方式的好处:避免了继承方式的单继承的局限性
在定义线程时,建议使用实现方式
继承Thread的线程代码存放在Thread子类的run方法中
实现Runnable线程代码存放在借口的子类run方法中

下面有一个需求:
银行有一个金库,有两个储户分别存300元,每次存一百,存3次

package first;
/*
 * 1.要明确哪些代码是多线程运行代码
 * 2.哪些数据是共享数据
 * 3.明确多线程运行代码中哪些语句是操作共享数据的
 */
public class BankDemo {
    public static void main(String[] args) {
        Cus cus1=new Cus();
        Cus cus2=new Cus();
        Thread t1=new Thread(cus1);
        Thread t2=new Thread(cus2);
        t1.start();
        t2.start();
    }
}
class Bank{
    private int sum;
    public synchronized void add(int n,String name){//同步函数
        sum+=n;
        System.out.println(name+" sum="+sum);
    }
}
class Cus implements Runnable{
    Bank b=new Bank();
    @Override
    public void run() {
        for(int i=0;i<3;i++)
            b.add(100,Thread.currentThread().getName());
    }

}

单例设计模式

//饿汉式
class Single{
    private static final Single s=new Single();
    private Single(){}
    public static Single getInstance(){return s;}
}
//懒汉式
//实例的延迟加载,但在多线程时会出错,要加锁
class Single{
    private static Single s=null;
    private Single(){}
    private static Single getInstance(){

        if(s==null){
            synchronized(Single.class){
                if(s==null){
                    s=new Single();
                }
            }
        }
        return s;
    }
}

下面来一个简单的死锁程序作为结束:
死锁:简单的讲就是a需要b的资源,同时b也需要a的资源,然后两个进程就在等待,发生了死锁

package first;
/*
 * 死锁
 */
public class DeadLockDemo {
    public static void main(String[] args) {
        Thread t1=new Thread(new TestDeadLock(true));
        Thread t2=new Thread(new TestDeadLock(false));
        t1.start();
        t2.start();
    }
}
class TestDeadLock implements Runnable{
    private boolean flag;
    public TestDeadLock(boolean flag) {
        this.flag=flag;
    }
    @Override
    public void run() {
        if (flag) {
            synchronized (MyLock.locka) {
                System.out.println("if locka");
                synchronized (MyLock.lockb) {
                    System.out.println("if lockb");
                }
            }
        }else{
            synchronized (MyLock.lockb) {
                System.out.println("else lockb");
                synchronized (MyLock.locka) {
                    System.out.println("else locka");
                }
            }
        }
    }

}
class MyLock{
    static Object locka=new Object();
    static Object lockb=new Object();
}

谢谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值