栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

java线程的使用

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java线程的使用

1.线程的基本概念

程序(program)是为完成特定任务、用某种语言编写的一组指令的集合。即指一 段静态的代码,静态对象。

进程(process)是程序的一次执行过程,或是正在运行的一个程序。是一个动态 的过程:有它自身的产生、存在和消亡的过程。——生命周期

如:运行中的QQ,运行中的MP3播放器

程序是静态的,进程是动态的 进程作为资源分配的单位,系统在运行时会为每个进程分配不同的内存区域

线程(thread),进程可进一步细化为线程,是一个程序内部的一条执行路径。

若一个进程同一时间并行执行多个线程,就是支持多线程的

线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器(pc),线程切换的开 销小

一个进程中的多个线程共享相同的内存单元/内存地址空间它们从同一堆中分配对象,可以 访问相同的变量和对象。这就使得线程间通信更简便、高效。但多个线程操作共享的系统资 源可能就会带来安全的隐患。

  • 关系

进程可以细化为多个线程

每个线程拥有自己独立的:栈区和程序计数器

多个线程共享一个程序中结构:方法区、堆

2.使用多线程的优点

背景:以单核CPU为例,只使用单个线程先后完成多个任务(调用多个方 法),肯定比用多个线程来完成用的时间更短,为何仍需多线程呢? 多线程程序的优点: 1. 提高应用程序的响应。对图形化界面更有意义,可增强用户体验。 2. 提高计算机系统CPU的利用率 3. 改善程序结构。将既长又复杂的进程分为多个线程,独立运行,利于理解和 修改

3.线程的使用

         继承Thread类的方式

         实现Runnable接口的方式

3.1方式1 Thread方式

1) 定义子类继承Thread类。

2) 子类中重写Thread类中的run方法。

3) 创建Thread子类对象,即创建了线程对象。

4) 调用线程对象start方法:启动线程,调用run方法。

  • 注意点:

1. 如果自己手动调用run()方法,那么就只是普通方法,没有启动多线程模式。

2. run()方法由JVM调用,什么时候调用,执行的过程控制都有操作系统的CPU 调度决定。

3. 想要启动多线程,必须调用start方法。

4. 一个线程对象只能调用一次start()方法启动,如果重复调用了,则将抛出以上 的异常“IllegalThreadStateException”。

  • 代码演示

public class demoCreat {
    public static void main(String[] args) throws InterruptedException {
//        3.创建thread类
        MyThread myThread = new MyThread();
        MyThread myThread1 = new MyThread();
        
        myThread.setPriority(Thread.MAX_PRIORITY);
        myThread1.setPriority(Thread.MIN_PRIORITY);
        Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
        
//        myThread.run();//切换运行,发现线程的main和Mythread名称都是一致的
        myThread.start();
        
        myThread.setName("我的线程000");
//        myThread.run();//错误


        myThread1.start();
        myThread1.setName("我的线程111");

        //main线程调度
        Thread.currentThread().setName("main线程");

        System.out.println("myThread存活状态:"+myThread.isAlive());
//        myThread1.join();//表示main线程阻塞,其他线程交替执行


        for (Integer i=0;i<100;i++){
            if (i%2==0) System.out.println(i+":"+Thread.currentThread().getName());
        }
    }
}
//1.创建 一个集成于thread类
class MyThread extends Thread{
    public MyThread(String name) {
        super(name);
    }
    public MyThread() {

    }
    
    @Override
    public void run() {
        for (Integer i=0;i<100;i++){
//            try {
//                sleep(10);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
            if (i%2==0) System.out.println(i+":"+Thread.currentThread().getName());

        }
    }
}
3.2Runnable方式

1) 定义子类,实现Runnable接口。

2) 子类中重写Runnable接口中的run方法。

3) 通过Thread类含参构造器创建线程对象。

4) 将Runnable接口的子类对象作为实际参数传递给Thread类的构造器中。

5) 调用Thread类的start方法:开启线程,调用Runnable子类接口的run方法。

代码演示

package com.dfp.dome1;


public class RunnableThread {
    public static void main(String[] args) {
        RThread rThread=new RThread();
        Thread thread=new Thread(rThread);
        
        thread.start();
    }


}
class RThread implements Runnable{

    @Override
    public void run() {
        for (Integer i=0;i<100;i++){
            if (i%2==0) System.out.println(i+":"+Thread.currentThread().getName());
        }
    }
}

3.3 抢票案例演示


public class WindowsDome {
    public static void main(String[] args) {
        DomeRunnable domeRunnable=new DomeRunnable();
        Thread t1=new Thread(domeRunnable);
        Thread t2=new Thread(domeRunnable);
        Thread t3=new Thread(domeRunnable);
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");
        t1.start();
        t2.start();
        t3.start();
    }
}
class DomeRunnable implements Runnable{
    private Integer tick=100;
    @Override
    public void run() {
        while (true){
            if (tick>0){
                System.out.println(Thread.currentThread()
                        .getName()+"售出车票为:"+tick);
                tick--;
            }else {
                break;
            }
        }
    }
}

结果

我们发现有个问题 票号100的同时被消费了。但是实际情况是不允许的

如果我们让窗口的线程沉睡了,还会出现-1号的票号问题(小概率概率出现)

 4.线程的生命周期 4.1生命周期的转换

 5.线程同步

1. 多线程出现了安全问题

2. 问题的原因: 当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有 执行完,另一个线程参与进来执行。导致共享数据的错误。

3. 解决办法: 对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以 参与执行。

5.1线程同步的方式

5.2 同步锁
  • 同步机制中的锁

在《Thinking in Java》中,是这么说的:对于并发工作,你需要某种方式来防 止两个任务访问相同的资源(其实就是共享资源竞争)。 防止这种冲突的方法 就是当资源被一个任务使用时,在其上加锁。第一个访问某项资源的任务必须 锁定这项资源,使其他任务在其被解锁之前,就无法访问它了,而在其被解锁 之时,另一个任务就可以锁定并使用它了。

synchronized的锁是什么?

 任意对象都可以作为同步锁。所有对象都自动含有单一的锁(监视器)。

 同步方法的锁:静态方法(类名.class)、非静态方法(this)  同步代码块:自己指定,很多时候也是指定为this或类名.class

注意:

 必须确保使用同一个资源的多个线程共用一把锁,这个非常重要,否则就 无法保证共享资源的安全

 一个线程类中的所有静态方法共用同一把锁(类名.class),所有非静态方 法共用同一把锁(this),同步代码块(指定需谨慎) 

5.3 方式一同步代码块演示

public class WindowsDome {
    public static void main(String[] args) {
        DomeRunnable domeRunnable=new DomeRunnable();
        Thread t1=new Thread(domeRunnable);
        Thread t2=new Thread(domeRunnable);
        Thread t3=new Thread(domeRunnable);
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");
        t1.start();
        t2.start();
        t3.start();
    }
}
class DomeRunnable implements Runnable{
    private Integer tick=100;
    Object object=new Object();//用做锁的对象,注意定义的位置保证唯一性
    @Override
    public void run() {
        while (true){
            //设置同步代码块,并且我们的DomeRunnable之创建一次意味着 objec对象也是创建一次。这么说在3个线程中object是唯一的
            synchronized (object){
                if (tick>0){
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread()
                            .getName()+"售出车票为:"+tick);
                    tick--;
                }else {
                    break;
                }
            }
        }
    }
}
5.4 同步方法演示

修改如下

 run方法中调用show方法

5.5 继承Thread的方式实现同步

因为通过继承thread的方式我们实现线程,这个方式创建一个线程就会创建3个类对于我的锁的机制而言就会冲突。我们主要修改一下这几个地方

将我们的锁设置为静态数据这样就是唯一的

 ​​​​​​​ 

或者在我们的同步方法加上静态 

public class WindowsDomeThread {
    public static void main(String[] args) {
        WindowExThread t1=new WindowExThread();
        WindowExThread t2=new WindowExThread();
        WindowExThread t3=new WindowExThread();
        t1.setName("t1窗口");
        t2.setName("t2窗口");
        t3.setName("t3窗口");
        t1.start();
        t2.start();
        t3.start();
    }
}
class WindowExThread extends Thread{
    private static Integer tick =100;
    private static Object lock=new Object();//静态
    @Override
    public void run() {
        while (true){
//            synchronized (lock){
//
//                if (tick>0){
//                    try {
//                        Thread.sleep(10);
//                    } catch (InterruptedException e) {
//                        e.printStackTrace();
//                    }
//                    System.out.println(Thread.currentThread()
//                            .getName()+"售出车票为:"+tick);
//                    tick--;
//                }else {
//                    break;
//                }
//            }
            show();
        }

    }
    private static synchronized void show(){
        if (tick>0){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread()
                    .getName()+"售出车票为:"+tick);
            tick--;
        }

    }
}

 线程执行同步代码块或同步方法时,程序调用Thread.sleep()、 Thread.yield()方法暂停当前线程的执行 线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程 挂起,该线程不会释放锁(同步监视器)。

应尽量避免使用suspend()和resume()来控制线程

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/948983.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号