多线程

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程相关的知识,希望对你有一定的参考价值。

java实现多线程的方式一:通过继承java.lang.Thread类(线程 是程序中的执行线程)来实现
  实现步骤:
    1.编写一个类继承Thread
    2.重写Thread类中的run方法
    3.使用start()方法启动线程
  注意:不要直接调用run()方法

public class MyThread extends Thread{
    @Override
    public void run() {
        for(int i=1;i<=10;i++){
            System.out.println("run---->"+i);
        }
    }
    
    public static void main(String[] args) {
        //创建对象
        MyThread myThread = new MyThread();
//        myThread.run();//方法的直接调用
        myThread.start();
        for(int i=1;i<=10;i++){
            System.out.println("main--->"+i);
        }
    }
}

实现多线程的第二种方式:通过实现java.lang.Runnable接口
  实现步骤:
    1.编写一个类实现Runnable接口
    2.重写run方法
    3.创建对象调用start()方法启动线程
  Thread(Runnable target) 分配新的 Thread 对象。

public class MyThread2 implements Runnable{
    private int num=10;
    @Override
    public void run() {
        for(int i=1;i<=10;i++){
//            System.out.println("run---->"+i);
            System.out.println(Thread.currentThread().getName()+"--"+i);
        }
    }
    
    public static void main(String[] args) {
        MyThread2 myThread = new MyThread2();
//        myThread.run();//方法的直接调用
        Thread thread = new Thread(myThread);//代理模式
        thread.start();
        for(int i=1;i<=10;i++){
//            System.out.println("main--->"+i);
            System.out.println(Thread.currentThread().getName()+"--"+i);
        }
    }
    
}

利用线程实现窗口售票,4个窗口同时售票,共有10张火车票,每个窗口有10人在等待。
要求:打印窗口名(当前正在运行的线程名)和所出售的为第几张票

public class SellTicket extends Thread{
    private  int num=10;
    @Override
    public void run() {
        for(int i=1;i<=10;i++){
            if(num>0){
                String threadName = Thread.currentThread().getName();
                System.out.println("窗口:"+threadName+",卖出了第"+(num--)+"张票");
            }
        }
    }
    
    public static void main(String[] args) {
        //窗口1在售票
        SellTicket sellTicket = new SellTicket();
        sellTicket.setName("A窗口");
        sellTicket.start();
        SellTicket sellTicket2 = new SellTicket();
        sellTicket2.setName("B窗口");//设置线程名称
        sellTicket2.start();
        SellTicket sellTicket3 = new SellTicket();
        sellTicket3.setName("C窗口");
        sellTicket3.start();
        SellTicket sellTicket4 = new SellTicket();
        sellTicket4.setName("D窗口");
        sellTicket4.start();
                
    }
    
}

利用线程实现窗口售票,4个窗口同时售票,共有10张火车票,每个窗口有10人在等待。
要求:打印窗口名(当前正在运行的线程名)和所出售的为第几张票
java中实现多线程有两种方式:
  方式一:继承Thread类
  缺点:
    1.应为java的继承为单继承,一旦使用继承的方式将无法在继承其他的类
    2.如果要启动多个线程,需要创建多个对象,无法完成数据共享。
      SellTicket sellTicket = new SellTicket();
      sellTicket.start();
      SellTicket sellTicket2 = new SellTicket();
      sellTicket2.start();

方式二:实现Runnable接口 推荐***
优点:1.在java中一个类是可以实现多个接口的,可以避免java单继承带来的影响。
2.可以创建一个对象,多个代理来启动线程,可以完成对象中的数据共享。
  SellTicket2 sellTicket = new SellTicket2();
  Thread thread = new Thread(sellTicket);
  thread.start();
  Thread thread2 = new Thread(sellTicket);
  thread2.start();

public class SellTicket2 implements Runnable{
    private  int num=10;
    @Override
    public void run() {
        for(int i=1;i<=10;i++){
            if(num>0){
                String threadName = Thread.currentThread().getName();
                System.out.println("窗口:"+threadName+",卖出了第"+(num--)+"张票");
            }
        }
    }
    
    public static void main(String[] args) {
        //窗口1在售票
        SellTicket2 sellTicket = new SellTicket2();
        Thread thread = new Thread(sellTicket);
        thread.start();
        
//        SellTicket2 sellTicket2 = new SellTicket2();
        Thread thread2 = new Thread(sellTicket);
        thread2.start();
        
//        SellTicket2 sellTicket3 = new SellTicket2();
        Thread thread3 = new Thread(sellTicket);
        thread3.start();
//        SellTicket2 sellTicket4 = new SellTicket2();
        Thread thread4 = new Thread(sellTicket);
        thread4.start();
                
    }
    
}


sleep():在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),对所操作的对象资源进行加锁。
yield():暂停当前正在执行的线程对象,并执行其他线程,对所操作的对象资源不会加锁。
join(): 等待该线程终止。当前线程执行结束,其他线程才能执行

public class ThreadA implements Runnable {
    String name;//线程名称
    public ThreadA(){
    }
    public ThreadA(String name){
        this.name=name;
    }
    
    @Override
    public void run() {
         for(int i=1;i<=10;i++){
//            try {
//                Thread.sleep(1);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
             System.out.println("线程"+name+"----->"+i);
         }
    }

}
public class ThreadB implements Runnable {
    String name;//线程名称
    public ThreadB(){
    }
    public ThreadB(String name){
        this.name=name;
    }
    
    @Override
    public void run() {
         for(int i=10;i>=1;i--){
//            try {
////                Thread.sleep(1);
//            } catch (InterruptedException e) {
//                    e.printStackTrace();
//            }
            System.out.println("线程"+name+"----->"+i);
         }
    }

}
public class TestThreadAB {
    public static void main(String[] args) {
        ThreadA threadA = new ThreadA("A");
        ThreadB threadB = new ThreadB("B");
        Thread t1 = new Thread(threadA);
        t1.start();
//        t1.yield();
        try {
            t1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Thread t2 = new Thread(threadB);
        t2.start();
        
    }
}

线程的状态:
  1.新生状态 :当使用new关键字创建线程后,在内存中分配空间
  2.就绪状态 : 当调用start()方法启动动线程时,此时CPU未分配时间片
  3.运行状态 : 当系统为该线程分配CPU资源(时间片)
  4.阻塞状态 : sleep方法,join方法,IO设备等待用户输入(input.next())
  5.死亡状态: 当线程正常运行结束或出现异常。
java.lang.Thread类:线程 是程序中的执行线程
  构造函数:
    Thread():分配新的 Thread 对象。
    Thread(Runnable target):分配新的 Thread 对象。
    Thread(String name): 分配新的 Thread 对象。默认名称:thread-xx
  常用的方法:
    getName()返回该线程的名称。
    setName(String name):设置线程名称
    getPriority() 返回线程的优先级。线程优先级[1,10] MAX_PRIORITY:10, MIN_PRIORITY:1, NORM_PRIORITY:5(默认)
    setPriority(int p):设置线程的优先级
    isAlive() 测试线程是否处于活动状态。 如果线程处于活动状态返回true,否则返回false
    currentThread():返回对当前正在执行的线程对象的引用。

public class TestThread implements Runnable{
    @Override
    public void run() {
        for(int i=0;i<10;i++){
            if(i%2==0){
                System.out.println(Thread.currentThread().getName()+"------"+i);
            }
        }
    }
    
    public static void main(String[] args) {
        TestThread testThread = new TestThread();
        Thread  thread = new Thread(testThread);//代理
        thread.setPriority(Thread.MIN_PRIORITY);//设置线程的优先级MAX_PRIORITY:10,MIN_PRIORITY:1,NORM_PRIORITY:5
        System.out.println("1.start()调用前是否为活动状态:"+thread.isAlive());//isAlive()-->false
        thread.start();
        System.out.println("2.start()调用前是否为活动状态:"+thread.isAlive());//isAlive()-->true
        System.out.println(thread.getName()+"线程优先级:"+thread.getPriority());//
        Thread  thread2 = new Thread(testThread);
        thread2.setPriority(Thread.MAX_PRIORITY);
        thread2.start();
        System.out.println(thread2.getName()+"线程优先级:"+thread2.getPriority());//
        
        
    }
}


同步(类似于排队的概念):
  优点:安全 缺点:效率低
  加锁:
同步代码块:对obj对象进行加锁,其他线程只有等待当前线程释放锁之后才能进行操作该对象及其属性。
  synchronized(obj){
  }
  obj:同步监视器,一般推荐使用共享资源作为同步监视器,同步监视器应该为引用类型的对象,不能是基本数据类型
同步方法(方法的同步):synchronized修饰方法
同步方法中不需要使用同步监视器,应为同步方法本身的同步监视器为this

同步监视器和同步方法的区别:
同步监视器对所有对象都起作用,同步方法只能针对当前对象本身起作用。

public class TicketThread2 implements Runnable {
    private int ticket=50;
    @Override
    public void run() {
            for(int i=0;i<1000;i++){
                sale();
            }
    }
    /**
     * synchronized修饰的方法:方法的同步
     */
    public synchronized void sale(){
        if(ticket>0){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"---->"+(ticket--));
        }
    }
    
    
    public static void main(String[] args) {
        TicketThread2 thread = new TicketThread2();
        Thread t1 = new Thread(thread);
        Thread t2 = new Thread(thread);
        Thread t3 = new Thread(thread);
        Thread t4 = new Thread(thread);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }

}
public class TicketThread implements Runnable {
    private int ticket=50;
    @Override
    public void run() {
            for(int i=0;i<1000;i++){
               synchronized (this) {//对当前对象同步
                    if(ticket>0){
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName()+"---->"+(ticket--));
                    }
            }
            
        }
    }
    
    public static void main(String[] args) {
        TicketThread thread = new TicketThread();
        Thread t1 = new Thread(thread);
        Thread t2 = new Thread(thread);
        Thread t3 = new Thread(thread);
        Thread t4 = new Thread(thread);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }

}
public class BankThread implements Runnable {
    private  double balance=1000;
    @Override
    public void run() {
        for(int i=0;i<10;i++){
//            getDraw();
            synchronized (this) {
                String name=Thread.currentThread().getName();
                System.out.println(name+"准备取款");
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if(balance>=100){
                    balance=balance-100;
                    System.out.println(name+"取款100,余额为"+balance);
                    System.out.println(name+"取款完成!");
                }else{
                    System.out.println(name+"余额不足!");
                }
            }
        }
    }

    public synchronized void getDraw(){
        String name=Thread.currentThread().getName();
        System.out.println(name+"准备取款");
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        if(balance>100){
            balance=balance-100;
            System.out.println(name+"取款100,余额为"+balance);
            System.out.println(name+"取款完成!");
        }else{
            System.out.println(name+"余额不足!");
        }
    } 
    
    public static void main(String[] args) {
        BankThread bankThread = new BankThread();
        Thread t1 = new Thread(bankThread,"张三");
        Thread t2 = new Thread(bankThread,"张三老婆");
        t1.start();
        t2.start();
    }
}

 

生产者与消费者(生产馒头与消费馒头)

/**
 *馒头类
 */
public class SteamBread {
    int id;
    
    public SteamBread(int id){
        this.id=id;
    }

    @Override
    public String toString() {
        return "SteamBread [id=" + id + "]";
    }
    
    
}
public class Producer implements Runnable{
    SyncStack ss;
    
    public Producer(SyncStack ss) {
        this.ss=ss;
    }
    
    @Override
    public void run() {
        // 开始生产馒头
        for(int i=1;i<20;i++){
            SteamBread steamBread = new SteamBread(i);//创建馒头
            ss.push(steamBread);
            System.out.println("生产了"+steamBread);
            try {
                Thread.sleep(10);//每生产一个馒头,睡觉10毫秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
/**
 * 消费者
 * 
 *
 */
public class Consume implements Runnable{
    SyncStack ss;
    
    public Consume(SyncStack ss) {
        this.ss=ss;
    }
    @Override
    public void run() {
        // 开始生产馒头
        for(int i=1;i<20;i++){
            SteamBread sb = ss.pop();
            System.out.println("消费了:"+sb);
            try {
                Thread.sleep(100);//每生产一个馒头,睡觉100毫秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
/**
 * 用于保存馒头的容器(匡)
 *
 */
public class SyncStack {
    int index;
    SteamBread[] sbStack = new SteamBread[10]; 
    
    /**
     * 生成者生成馒头放入框中,相当于入栈
     * @param sb
     */
    public synchronized void push(SteamBread sb){
        //匡已经满了
        if(index==sbStack.length){
            try {
                this.wait();//让生产者线程等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.notify();//唤醒在此对象监视器上等待的单个线程。唤醒消费者线程
        sbStack[index]=sb;//将馒头放入匡中
        index++;
    }
    
    /**
     * 消费者从匡中获取馒头,相当于出栈
     * @return
     */
    public synchronized SteamBread pop(){
        //判断匡中是否还有馒头
        if(index==0){
            try {
                this.wait();//让消费者线程等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.notify();//唤醒生成者生成馒头
        index--;
        return sbStack[index];
    }
    
}
public class Test {
    public static void main(String[] args) {
        SyncStack ss = new SyncStack();//创建盛放馒头的容器
        Producer producer = new Producer(ss);//创建生成者线程
        Consume consume = new Consume(ss);//创建消费者线程
        Thread t1 = new Thread(producer);
        Thread t2 = new Thread(consume);
        t1.start();//启动线程
        t2.start();
    }
}

 

以上是关于多线程的主要内容,如果未能解决你的问题,请参考以下文章

线程学习知识点总结

多个请求是多线程吗

python小白学习记录 多线程爬取ts片段

多线程编程

多线程编程

python多线程