java高级-线程

1.什么是线程

1.1程序

程序是指为了完成某一套特定的任务而编写的具体文件

1.2进程

进程是程序的一次执行过程,是系统运行的基本单位。每个进程占有某些系统资源(CPU、内存等)

1.3线程

线程与进程类似,线程是比进程更小的执行单位。一个进程在其执行的过程中,产生多个线程。多个线程是共享同一块内存空间和一组系统资源,所以多个线程相互切换工作时,负担比进程小的多,线程也被称为轻量级进程。

2.如何创建线程

2.1通过继承Thread来重写run方法
public class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("run==="+i);
        }
    }
}

调用start方法启动新线程

注意:如果直接调用run()方法,不会创建一个新线程,而只会在当前线程中执行run方法的内容

public class TestThread {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();//创建线程对象
        myThread.start();//启动线程方法

        for (int i = 0; i < 10; i++) {
            System.out.println("main============"+i);
        }
    }
}

运行结果:

main============0
main============1
main============2
main============3
run===0
run===1
run===2
run===3
run===4
run===5
main============4
run===6
main============5
run===7
run===8
run===9
main============6
main============7
main============8
main============9

Process finished with exit code 0
2.2通过实现Runnable来重写run方法(推荐)

避免了单继承的限制,可以扩展业务

public class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("run====="+i);
        }
    }
}

创建方式与上面一样都调用.start()方法来创建一个新线程。但注意的是实现Runnable来使用时,要创建一个线程,再将这个实例传给这个线程

public class TestRunnable {
    public static void main(String[] args){
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);//创建线程传递myRunnable
        thread.start();
        for (int i = 0; i < 10; i++) {
            System.out.println("main============"+i);
        }
    }
}

3.线程的主要方法

3.1获取设置当前线程名称

getName()获取当前线程名称

setName()设置当前线程名称

public class TestRunnable {
    public static void main(String[] args){
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);//创建线程传递myRunnable
        thread.start();//启动线程
        thread.setName("run线程");//设置线程name

        Thread.currentThread().setName("主线程");//设置主线程name
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"============"+i);//获取主线程name
        }

    }
}
public class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"====="+i);//获取run线程name
        }
    }
}
3.2休眠

sleep(),这个方法用来让当前线程休眠指定的毫秒数

public class MyRunnable implements Runnable{
    @Override
    public void run() {
        try {
            Thread.sleep(1000);//休眠一秒
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"====="+i);//获取run线程name
        }
    }
}
3.3yield

让出当前进程时间片,使其他相同优先级的线程有机会执行,这个会尽量平均分配cpu资源

public class MyRunnable implements Runnable{
    @Override
    public void run() {
        Thread.yield();//放弃cpu资源,允许其他线程访问
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"====="+i);//获取run线程name
        }
    }
}
3.4join

.join()可以使一个线程等待另一个线程结束

public class TestRunnable {
    public static void main(String[] args) throws InterruptedException {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);//创建线程传递myRunnable
        thread.start();//启动线程
        thread.setName("run线程");//设置线程name
        Thread.currentThread().setName("主线程");//设置主线程name
        
        thread.join(); //主线程会等run线程结束
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"============"+i);//获取主线程name
        }
    }
}
3.5优先级

setPriority(1-10)用于设置优先级,数字越高优先级越高,更有可能被调用。

public class TestRunnable {
    public static void main(String[] args) throws InterruptedException {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread1 = new Thread(myRunnable,"线程1");//创建线程传递myRunnable
        Thread thread2 = new Thread(myRunnable,"线程2");
        Thread thread3 = new Thread(myRunnable,"线程3");

        thread3.setPriority(10);
        thread2.setPriority(5);
        thread1.setPriority(1);

        thread1.start();//启动线程
        thread2.start();
        thread3.start();
        
    }
}

会发现优先级高的被调用的可能性高一点

4.守护线程

通过调用setDaemon(true)来实现守护线程,当用户线程执行完毕后,守护线程也会相应结束

public class TestRunnable {
    public static void main(String[] args) throws InterruptedException {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread1 = new Thread(myRunnable,"线程1");//创建线程传递myRunnable
        thread1.setDaemon(true);//设置为守护线程
        thread1.start();//启动线程
        for (int i = 0; i < 1; i++) {
            System.out.println(Thread.currentThread().getName()+"====="+i);
        }

    }
}
public class MyRunnable implements Runnable{
    @Override
    public void run() {

        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName()+"====="+i);//获取run线程name
        }
    }
}

这个主线程执行一次,线程1执行二十次,但主线程一结束,线程二也会相应结束

5.线程安全问题

多个线程同时修改一个变量

案例1:四个窗口共卖100张票

public class MyRunnable implements Runnable{
    private static int ticket=100;
    @Override
    public void run() {
        synchronized (this){
            while (true){
                if (ticket>0){
                    ticket--;
                    System.out.println(Thread.currentThread().getName()+"卖了一张票,还剩"+ticket);
                }else {
                    break;
                }
            }
        }
    }
}
public class TestRunnable {
    public static void main(String[] args){
        MyRunnable myRunnable = new MyRunnable();
        Thread thread1 = new Thread(myRunnable,"A窗口");//创建线程传递myRunnable
        Thread thread2 = new Thread(myRunnable,"B窗口");//创建线程传递myRunnable
        Thread thread3 = new Thread(myRunnable,"C窗口");//创建线程传递myRunnable
        Thread thread4 = new Thread(myRunnable,"D窗口");//创建线程传递myRunnable
        thread1.start();//启动线程
        thread2.start();//启动线程
        thread3.start();//启动线程
        thread4.start();//启动线程


    }
}

运行几次发现问题,有重卖和超卖的现象,这里就是线程安全问题造成的

 案例2: A线程将“Hello”存入数组;B线程将“World”存入数组。

public class TestRun {
    private static String[] arr=new String[2];
    private static int index=0;

    public static void main(String[] args) throws InterruptedException {
       Thread t01= new Thread(new Runnable() {
            @Override
            public void run() {
                if (arr[index]==null){
                    arr[index]="hello";
                    index++;
                }
            }
        });
        Thread t02= new Thread(new Runnable() {
           @Override
           public void run() {
               if (arr[index]==null){
                   arr[index]="wold";
                   index++;
               }
           }
       });
        t01.start();
        t02.start();
        t01.join();
        t02.join();
        System.out.println(Arrays.toString(arr));

    }
}

四种结果

a.[hello,null] b.[hello,world] c.[world,hello] d.[world,null]

6.锁

上面的线程安全问题我们可以用到锁,凡是用锁,操作的代码都是原子性

6.1自动锁

synchroized

可以修饰代码块、静态方法、普通方法

public class MyRunnable implements Runnable {
    private static int ticket = 100;
    @Override
    public void run() {
        aaa();
    }
    public synchronized void aaa(){ //修饰方法
        while (true) {
                if (ticket > 0) {
                    ticket--;
                    System.out.println(Thread.currentThread().getName() + "卖了一张票,还剩" + ticket);
                } else {
                    break;
                }

        }
    }
}

也可以synchroized(Object object){

}

object为同一个object对象

public class MyRunnable implements Runnable {
    private static int ticket = 100;
    private Object aa = new Object();
    @Override
    public void run() {
        while (true) {
            synchronized (aa) {
                if (ticket > 0) {
                    ticket--;
                    System.out.println(Thread.currentThread().getName() + "卖了一张票,还剩" + ticket);
                } else {
                    break;
                }
            }
        }
    }
}

解决了多卖和重卖的问题

6.2手动锁

lock只能用在代码块

创建Lock实例

Lock lock=new ReetrantLock();

加锁

lock.lock();

解锁

lock.unlock();
public class MyRunnable implements Runnable {
    private static int ticket = 100;
    private Lock lock = new ReentrantLock();
    @Override
    public void run() {
        while (true) {
                lock.lock();//加锁
                if (ticket > 0) {
                    ticket--;
                    System.out.println(Thread.currentThread().getName() + "卖了一张票,还剩" + ticket);
                } else {
                    break;
                }
                lock.unlock();//解锁
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值