java线程知识总结

一、线程相关概念

1.进程:进程是程序的一次执行过程,或是正在运行的一个程序,进程是动态的,有它自己的产生、存在和消亡的过程。

2.线程:线程是由进程创建的,是进程的一个实体。

单线程:同一时刻,只能执行一个线程。

多线程:同一时刻,允许执行多个线程。

并发:同一时刻,多个线程交替执行,给人一种多个线程同时执行的错觉,单核cpu实现的任务就是并发。

并行:同一时刻,多个线程同时执行,多核cpu可以实现并行。

二、线程的基本使用

1.示例如下(通过继承Thread来创建线程):

public class Thread01 {
    public static void main(String[] args) {
        Cat cat = new Cat();//线程产生
        cat.start();//启动线程
        System.out.println("主线程"+Thread.currentThread().getName()+"继续");// main线程的名字
        for (int i = 0; i < 10; i++) {
            System.out.println("main线程"+i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
class Cat extends Thread{
    int times=0;
    @Override
    public void run() {
        while(true){
            System.out.println("Cat hello"+(times++)+Thread.currentThread().getName());
            try {
                sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(times==8){
                break;
            }
        }
    }
}

1)当一个类继承了Thread类时,这个类就可以当作线程使用,我们可以重写run()方法,实现自己的业务逻辑,以上示例Cat继承了Thread。

2)Cat.run()方法只是一个普通的方法,我们要启动线程,得调用start()方法。

3)当启动子线程时,主线程不会阻塞,会继续执行,此时主线程和子线程交替执行。

4)java是单继承的,所以当一个类继承了Thread后别的类就不能继承了,所以有另外一个创建线程的方法,即通过继承Runnable接口来创建线程。

2.通过实现接口Runnable接口来开发线程:

public class Thread02 {
    public static void main(String[] args) {
        Apple apple = new Apple();//这里不能直接apple.start()
        Thread thread=new Thread(apple);
        thread.start();
    }
}
class Apple implements Runnable{
    int count=10;
    @Override
    public void run() {
        while(count>0){
            System.out.println(Thread.currentThread().getName()+"苹果数量:"+(count--));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

3.多线程执行

继承Thread和实现Runnable的区别:

在本质上,继承Thread或实现Runnable没有区别,Thread在底层也实现了Runnable接口。实现Runnable接口方式更加适合多个线程共享一个资源,并且可以避免单继承的限制。

模拟三个窗口同时售票100张:

public class Thread03 {
    public static void main(String[] args) {
        SellTicket sellTicket = new SellTicket();
        new Thread(sellTicket,"窗口1").start();
        new Thread(sellTicket,"窗口2").start();
        new Thread(sellTicket,"窗口3").start();
    }
}
class SellTicket implements Runnable{
    private static int ticketNum=100;//共享资源
    @Override
    public void run() {
        while (true){
            if(ticketNum<=0){
                System.out.println("票已经售完");
                break;
            }
            System.out.println(Thread.currentThread().getName()+"正在卖出第"+(ticketNum--)+"张票");
        }
    }
}

4.线程常用方法

1)interrupt()中断线程,并没有真正结束线程,一般用于中断正在休眠的线程。

2)yield:线程的礼让,线程礼让的时间不确定,所以不一定能礼让成功。

3)join:线程的插队,线程一旦插队成功,则一定先进行插队线程的所有任务。

5.用户线程和守护线程

用户线程:任务线程,当线程的任务执行完或通知方式结束。

守护线程:为用户线程服务,当用户线程执行完,守护线程自动结束,常见的守护线程有:垃圾回收机制。

6.线程同步机制

1)在多线程编程,有一些敏感数据不允许被多个线程同时访问,此时就用到线程同步访问,保证数据在任何时刻,最多有一个线程访问,从而保证数据完整性。

2)当有一个线程对内存地址操作时,其他线程都不能对此内存地址进行操作,直到该线程完成访问,其他线程才能对该内存进行操作。

同步代码块:

sychronized(对象){//只有得到对象的锁才能操作同步代码
    //需要被同步的代码块
}

还可以放在方法声明中,表示整个方法为同步代码块:

public synchronized void m(String name){
    //需要被同步的代码块
}

7.分析同步原理

1)在java语言中引入了互斥锁的概念,来保证共享数据操作的完整性。

2)每个对象都对应于一个可称为互斥锁的标记,这个标记保证在任意时刻,只有一个线程访问该对象。

3)关键字sychronized来与互斥锁联系,当一个对象被sychronized修饰时,表明该对象在任意时刻只能由一个线程访问。

4)同步方法的局限性:降低了程序执行效率。

5)非静态的同步方法可以为this,也可以是其他对象,要求是同一个对象。

6)静态的同步方法的锁为当前类本身。

8.线程的死锁

多个线程都占用了对方的锁资源不肯相让,导致了死锁。

模拟死锁:

public class DeadLock_ {
    public static void main(String[] args) {
        example A = new example(true);
        A.setName("线程A");
        example B = new example(false);
        B.setName("线程B");
        A.start();
        B.start();
    }
}
class example extends Thread{
    Object o1=new Object();
    Object o2=new Object();
    boolean loop;
    public example(boolean loop) {
        this.loop = loop;
    }
    @Override
    public void run() {
        if(loop){
            synchronized (o1) {
                System.out.println("进入1" + Thread.currentThread().getName());
                synchronized (o2) {
                    System.out.println("进入2" + Thread.currentThread().getName());
                }
            }
        }else{
            synchronized (o2) {
                System.out.println("进入3" + Thread.currentThread().getName());
                synchronized (o1) {
                    System.out.println("进入4" + Thread.currentThread().getName());
                }
            }
        }
    }
}

分析:当loop为true时,A线程先获取o1线程锁,当获取不到o2线程锁时会阻塞。当loop为false时,B线程先获取o2线程锁,获取不到o1线程锁时会阻塞。造成线程死锁。

8.释放锁

以下情况会释放锁:

1)当前线程的同步代码、同步方法块执行结束。

2)当前线程的同步代码块、同步方法执行时遇到break或return。

3)当前线程的同步代码块、同步方法执行时遇到了线程对象的wait()方法,当前程序暂停,锁释放。

4)当前线程的同步代码、同步方法块遇到未处理的Error或Exception,导致异常结束。

以下情况不会释放锁:

1)线程执行同步代码块或同步方法时,调用sleep()或yield()暂停当前程序的执行。

2)线程执行同步代码块或同步方法时,调用该线程的suspend()方法将该线程挂起。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值