多线程

多线程

什么是程序:一组独立功能的静态的计算机指令;

进程:向系统申请资源的独立单位

进程是一次程序动态的运行过程,它有就绪、阻塞、运行等状态

案例:开了一个QQ,就是开了一个进程,再打开迅雷,又开了一个进程,那我们在QQ上可以传输文字、语音、广告弹出,理解为一个线程,换句话理解就是线程是任务。一个进程可以管理多个线程,进程里面至少包括一条线程。通俗来讲,进程是领导,线程是员工,进程管理线程,进程本身不执行,只是为线程提供运行环境申请内存空间。

什么是线程:

线程是程序执行的一条路径,一个进程中可以包含多条线程。

多线程:

(1)一个进程里面同时执行多个任务

(2)一个进程里面至少有一个线程

(3)开启多个线程是为了同时执行多个任务,也是同时执行多部分代码。

利弊

好处:解决了多任务同时执行的问题

弊端:线程切换花费额外的资源,同时切换也是一个耗时的步骤

多线程并行和并发的区别

并行就是两个(或多个)任务同时进行

并发是指两个任务都请求运行,而处理器只能接受一个任务,就是把两个任务安排轮流进行,由于时间间隔较短,使人感觉两个任务都在运行。

Java程序运行原理和JVM的启动是多线程的吗?

Java程序运行原理

Java命令会启动java虚拟机,启动JVM,等于启动了一个应用程序,也就是启动了一个进程。该进程会自动启动一个 “主线程” ,然后主线程去调用某个类的 main 方法。

JVM的启动是多线程的吗

Ø JVM启动至少启动了垃圾回收线程主线程,所以是多线程的。

Ø main方法的代码执行的位置就是在主线程(路径)

Ø 一个进程有多个线程

Ø finalize()这个方法在子线程(垃圾回收线程)执行

如何创建线程:

(1)将类声明为Thread的子类

(2)然后这个子类重写run方法

(3)创建子类对象

(4)开启线程

 

一般来讲,少时的方法都不放在主线程里,

常用的线程的属性:

Name--获取线程的名字,默认为Thread-x

这种方式开启多线程,要求该类不能继承其他的父类,因为java是单继承。但我们可以用接口的方式来扩展。

第二种方法:创建一个类,实现runnable接口,实现run方法,创建线程Thread(ThreadRunnable),开启。


public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"线程");
    }
}

public class Test {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable,"崔浩麒");
        thread.start();
    }
}

一般都是使用第二种方法创建线程。

两种方式的区别:

继承Thread : 由于子类重写了Thread类的run(), 当调用start()时直接找子类的run()方法

实现Runnable : 构造函数中传入了Runnable的引用, 有个成员变量记住了它, 调用run()方法时内部判断成员变量Runnable的引用是否为空。

 

注意:线程的开启使用start,而不是用run,如果直接使用run,那程序的执行就和函数调用没有区别,一直在调用主线程。

 

 

 

多线程安全的条件:

(1)多个线程同时访问共享资源(共享数据)

(2)操作共享数据的代码有多条

解决办法:

对于不同执行的代码,我们只能保证当有一个线程执行的时候,其它线程不能进入执行。

类似公共厕所,进入之后上锁,离开的时候开锁,这就保证里面只有一个人在使用

Java中提供给我们一种“同步代码块”可以解决这个问题

好处:解决了线程安全的问题

坏处:相对降低了效率,以为每次都要去判断是否有同步锁

线程方法:

线程休眠:

Thread.sleep(毫秒), 控制当前线程休眠若干毫秒

1= 1000毫秒

1= 1000毫秒* 1000微妙 * 1000纳秒(1000000000

获取线程名字和设置名字

Ø 通过ThreadgetName()方法获取线程对象的名字

Ø 通过setName(String)方法可以设置线程对象的名字

Ø 通过构造函数可以传入String类型的名字

 获取当前线程的对象

Ø Thread.currentThread()方法用于获取当前线程对象

Ø 在不同的方法中,获取的线程对象名称是有可能不一样的

Ø main中获取的是主线程对象

Ø 在子线程的run方法中获取的是子线程对象

线程优先级:


public class Test implements Runnable {
    private String name;
    Test(String name){
        this.name = name;
    }
    @Override
    public void run() {
        for (int i =0;i<5;i++){
            System.out.printf("%s,%d",name,i);
            System.out.println( );
        }
        System.out.printf("%s结束!!!",name);
        System.out.println( );
    }
}


public class Demo {
    public static void main(String[] args) {
        Test test = new Test(" 骨灰盒");
        Test test1 = new Test("总经理");
        Test test2 = new Test("棺材板");

        Thread thread = new Thread(test);
        Thread thread1 = new Thread(test1);
        Thread thread2 = new Thread(test2);
        thread2.setPriority(Thread.MAX_PRIORITY);
        thread.setPriority(Thread.NORM_PRIORITY);
        thread1.setPriority(Thread.MIN_PRIORITY);
        thread.start();
        thread1.start();
        thread2.start();
    }
}

 

守护线程

Ø setDaemon(), 设置一个线程为守护线程, 该线程不会单独执行, 当其他非守护线程都执行结束后, 自动退出

Ø 特点:男守护女,女的死,男的也不想活了

线程安全


public class Solder implements Runnable {
    @Override
    public void run() {
        while (true) {
            synchronized (String.class) {//同步枷锁
                int no = TicketPool.getEmpty();
                System.out.println(Thread.currentThread().getName() + "查到了" + no + "号票");
                if (no == -1) {
                    System.out.println("无票");
                    break;
                }
                try {
                    Thread.sleep(( int ) (Math.random() * 50));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                TicketPool.sold(no);
                System.out.println(Thread.currentThread().getName() + "售出了" + no + "号票");
            }
            }
    }
}

 


public class TicketPool {
    private static int num;
    private static boolean[]ticket;
    static {
        num = 100;
        ticket = new boolean[num];
        Arrays.fill(ticket,false);
    }

    /**
     * 查票
     * @return 票号-1代表无票
     */
    public static  int getEmpty(){
        for (int i = 0;i<ticket.length;i++){
            if (ticket[i]==false){
                return i;
            }
        }
        return -1;
    }

    /**
     * 售票
     * @param index
     */
    public static void sold(int index){
        ticket[index]=true;
    }
}

 


public class Test {
    public static void main(String[] args) {
        Solder solder = new Solder();
        Thread thread = new Thread(solder,"悟空");
        Thread thread2 = new Thread(solder,"悟能");
        Thread thread3 = new Thread(solder,"悟净");
        thread.start();
        thread2.start();
        thread3.start();
    }
}

 

加入线程

Ø join(), 当前线程暂停, 等待指定的线程执行结束后, 当前线程再继续

Ø join(int), 可以等待指定的毫秒之后继续


public class InsertThread implements Runnable {
    private String name;
    public InsertThread(String name){
        this.name = name;
    }
    @Override
    public void run() {
            for (int i = 0; i < 5; i++) {
                System.out.printf("%s,%d\n", name, i);
            }
        System.out.printf("%s结束!!!\n", name);
    }
}


public class Test {
    public static void main(String[] args) throws InterruptedException {
        InsertThread insertThread = new InsertThread("张三");
        Thread thread = new Thread(insertThread);
        thread.start();
        for (int i = 0;i<5;i++){
            System.out.println(Thread.currentThread().getName());
            if (i==3){
                thread.join();
            }
        }
    }
}

 

Ø 

线程让出

Ø yield() 让出cpu
public class Talk implements Runnable {
    private String name;

    Talk(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.printf("%s,%d\n", name, i);
            Thread.yield();

        }
        System.out.printf("%s结束!!!\n", name);

    }
}

 


public class Demo {
    public static void main(String[] args) {
        Talk talk = new Talk("崔好奇");
        Talk talk1 = new Talk("崔好气");
        Thread thread1 = new Thread(talk1);
        Thread thread = new Thread(talk);
        thread.start();
        thread1.start();
    }
}

 

线程优先级

Ø setPriority()设置线程的优先级

Ø 默认优先级是5,最小优先级1,最高优先级10

Ø 可以设置234

Ø Thread里面有静态常量

线程与同步

什么是同步

Ø 同步就是加锁不让其它人访问

Ø synchronized指的就是同步的意思

什么情况下需要同步

Ø 当多线程并发, 我们希望某一段代码执行的过程中CPU不要切换到其他线程工作. 这时就需要同步,否则会有线程安全问题.

 

同步代码块

Ø 使用synchronized关键字加上一个锁对象来定义一段代码, 这就叫同步代码块

Ø 多个同步代码块如果使用相同的锁对象, 那么他们就是同步的

Ø 使用同步锁时,应该尽是让锁的范围小点,才能提高性能

同步方法

Ø 使用synchronized关键字修饰一个方法, 该方法中所有的代码都是同步的

Ø 非静态同步方法的锁是:this

Ø 静态同步方法的锁是:字节码对象(xx.class)

锁的总结

/**

 * 1.锁问题:

 *  同步中,锁最好同一个对象,如果不是同一对象,还是会有线程安全问题

 *   锁:this,代当前对象

 *   锁:如果 new 对象,就不是同一把锁

 *   锁:字节码对象 String.class,内存中,只有一个字节码对象

 *   开发中:一般都是this

 *   

 * 2.在方法内部声明synchronized的就是 “同步代码块”

 *

 * 3.在声明方法的时候,添加 synchronized,就是同步方法

 *    》如果是非静态方法,锁就是this

 *    》如果是静态方法,锁就当前类的字节码对象

 *      //TicketTask.class

     public static synchronized void test1(){}

 *  

 * 4.同步使用的建议:

 *   同步加锁的时候,尽量让锁住的代码范围小一点,这样可以让其它线程等待时间少一点,性能高

 *

 */

死锁

Ø 死锁就是大家都抱着锁,不释放

public class Demo {

static String s1 = "筷子左";

static String s2 = "筷子右";

public static void main(String[] args) {

new Thread(){

public void run() {

while(true){

synchronized (s1) {

System.out.println("线程A 拿到" + s1 + " 等待" + s2);

synchronized (s2) {

System.out.println("线程A 拿到" + s2 + " 开吃");

}

}

}

};

}.start();

new Thread(){

public void run() {

while(true){

synchronized (s2) {

System.out.println("线程B 拿到" + s2 + " 等待" + s1);

synchronized (s1) {

System.out.println("线程B 拿到" + s1 + " 开吃");

}

}

}

};

}.start();

}

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

double_lifly

点喜欢就是最好的打赏!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值