Java--线程

目录

程序,进程,线程

创建线程

Thread类中的方法

线程优先级

线程状态

守护线程

多线程的概念

线程同步

Lock

线程通信

新增创建线程方式


程序,进程,线程

程序:为完成特定的功能,使用计算机语言编写的一系列的指令集合,即静态代码

进程:运行中的程序,被加载到内存里,是操作系统分配资源的最小

线程:是进程中最小的执行单元(任务),是操作系统进行任务调度的最小单位,隶属于线程

线程和进程的关系:

1.一个进程可以包含多个线程,一个线程只能属于一个进程,线程不能脱离进程

而独立运行;

2.每一个进程至少包含一个线程(称为主线程);在主线程中开始执行程序,

java程序的入口main()方法就是在主线程中被执行的。

3.在主线程中可以创建并启动其它的线程;

4.一个进程内的所有线程共享该进程的内存资源

创建线程

public class Demo1 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println(Thread.currentThread().getName()+i);
        }
    }
}
public class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("myTread"+i);
        }
    }
}
public class Test {
    public static void main(String[] args) {
        System.out.println("main开始");
        MyThread myThread=new MyThread();
        myThread.start();
        Thread thread=new Thread();
        thread.run();
        Thread thread1=new Thread();
        thread.run();
        System.out.println("main结束");
    }
}

区别:

继承Thread:线程代码存放Thread子类run方法中

实现Runnable:线程代码存在接口的子类的run方法中

实现Runnable的好处:

1.避免了单继承的局限性

2.多个线程可以共享同一个接口实现类的对象,非常适合多个相同线程来处理同一份资源

Thread类中的方法

public class Test1 implements Runnable{
    @Override
    public void run() {
        Test1 printNum= new Test1();
        System.out.println("线程开始");
        for (int i = 0; i < 1000; i++) {
            Thread thread=new Thread(printNum,"线程1");
            //thread.run();//线程任务执行的方法
            thread.start();//启动线程
            Thread thread1=new Thread(printNum,"线程2");
            //  thread.join();//等待线程结束
            thread1.start();
            //thread.getName();//获得线程的名称
            // thread.setName();//获得线程的名称
            //thread.setPriority(10);//设置优先级
            //thread.getPriority();//获得优先级
            //Thread(target)//创建线程,并指定任务
            //Thread(target,name)//获取到当前所在的线程
            //currentThread()  //获取到当前所在线程
            //yield()//线程让步
            //sleep(1000)//线程休眠,指定的时间(毫秒单位)
        }
    }
}

线程优先级

计算机只有一个CPU,各个先线程轮流获得CPU使用权,才能执行任务

优先级较高的线程有更多获得CPU的机会,反之亦然

优先级用整数表示,取值范围是1-10,一般情况下,线程的默认优先级都是5,但是也可以通过setPriority和getPriority方法来设置或返回优先级

设置优先级后,不一定优先级高的,每次都是优先执行,需要操作系统调用

public class PrintNum implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}
public class Test {
    public static void main(String[] args) {
        PrintNum printNum=new PrintNum();
        Thread thread=new Thread(printNum);
        thread.start();
        Thread thread1=new Thread(printNum);
        thread1.start();
    }
}

线程状态

 

新建:当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态

就绪:处于新建状态的线程被start()后,将进入线程队列等待CPU时间片,此时它具备了与逆行的条件,只是没分配到CPU资源

运行:当就绪的线程被调度并获得CPU资源时,便进入运行状态,run()方法定义了线程的操作和功能

阻塞:在某种特殊情况下,被认为挂起或执行输入输出操作时,让出CPU并临时终止自己的执行,进入阻塞状态

死亡:线程完成了它的全部工作或线程被提前强制性的终止或出现异常导致结束

守护线程

public class DaemonThread implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            while (true) {
                System.out.println("我是守护线程,一直守护其他线程" + i);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
public class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("我是小线程"+i);
        }
        }
    }

public class Test {
    public static void main(String[] args) {
        MyThread myThread=new MyThread();
        Thread thread=new Thread(myThread);
        thread.setDaemon(true);
        thread.start();
        DaemonThread daemonThread=new DaemonThread();
        Thread thread1=new Thread(daemonThread);
        thread1.start();
    }
}

Java中的线程分为两类:用户线程和守护线程

任何一个守护线程都是整个 JVM 中所有非守护线程的保姆 , 只要当前 JVM 实例中尚存在
任何一个非守护线程没有结束,守护线程就全部工作;

多线程的概念

程序中包含多个执行单元,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个线程创建多个并执行的线程来完成各自的任务

优点:

1.一个应用程序内部,可以同时执行多个任务

2.提高程序处理能力,响应速度提高

3.提高CPU利用率,压榨硬件的价值

4.提升程序结构

缺点:

1.线程也是程序,所以线程需要占用内存,线程越多占用内存也越多

2.多个线程对同一个共享资源进行访问,对CPU要求提高了,提升硬件性能改善

3.多线程需要协调和管理,所以需要CPU的时间跟踪线程

线程同步

并发:在一个时间段内,多个事情一次执行

并行:在同一个时间节点上,多个事情同时进行

解决办法:排队+锁

同步锁,在高级层里面解决的,用synchronized关键字修饰

synchronized修饰一段代码块

synchronized(同步对象/锁对象)--用来记录有没有线程进入到同步代码块,要求是唯一的

synchronized修饰非静态的方法时,锁对象是this

synchronized修饰静态的方法时,锁对象是当前类的class对象

法一:

public class TicketThread extends Thread {
    static int num = 10;
    static Object object = new Object();
    @Override
    public void run() {
        synchronized (object) {
            while (true) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (num >0) {
                    System.out.println(Thread.currentThread().getName() + ":" + num--);
                } else {
                    break;
                }
            }
        }
    }
}
public class Test {
    public static void main(String[] args) {
        TicketThread ticketThread = new TicketThread();
        Thread thread = new Thread(ticketThread,"窗口一" );
        Thread thread1 = new Thread(ticketThread,"窗口二");
        thread.start();
        thread1.start();
    }
}

法二:

public class PrintTicket implements Runnable{
    int num=10;
    @Override
    public void run() {
            while (true){
                synchronized (this){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (num>0){
                    System.out.println(Thread.currentThread().getName()+":"+num);
                    num--;
                }else {
                    break;
                }
            }
        }
    }
}
public class Test {
    public static void main(String[] args) {
        PrintTicket ticket=new PrintTicket();
        Thread thread=new Thread(ticket,"窗口1");
        Thread thread1=new Thread(ticket,"窗口2");
        thread.start();
        thread1.start();
    }
}
 private synchronized void ptint() {
        if (num>0){
            System.out.println(Thread.currentThread().getName()+":"+num);
            num--;
        }
    }
}
同步执行过程
1.第一个线程访问,锁定同步对象,执行其中代码.
2.第二个线程访问,发现同步对象被锁定,无法访问.
3.第一个线程访问完毕,解锁同步对象.
4.第二个线程访问,发现同步对象没有锁,然后锁定并访问

Lock

ReentrantLock类实现了Lock,它拥有与synchronized相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以显式加锁、释放锁

Reentrantlock和synchronied的区别:

synchronied是关键字,实现是依靠底层编译后的指令来控制的

synchronied可以修饰代码块和方法

synchronied是隐式锁,自动添加,同步代码块执行完毕或者出现锁异常,锁会自动释放

Reentrantlock是Java.util.concurrent.locks包下的一个类,是依靠Java代码实现的控制

Reentrantlock只能修饰代码块

Reentrantlock是手动添加,手动释放

死锁--DieLock

不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,形成了死锁

出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续

public class DieLockThread implements Runnable {
    boolean flag;
    static Object objA = new Object();
    static Object objB = new Object();

    public DieLockThread(boolean flag) {
        this.flag = flag;
    }

    @Override
    public void run() {
        if (flag) {
            synchronized (objA) {
                System.out.println(objA);
            }
            synchronized (objB) {
                System.out.println(objB);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        } else {
            synchronized (objB) {
                System.out.println(objB);
            }
            synchronized (objA) {
                System.out.println(objA);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
public class Test {
    public static void main(String[] args) {
        DieLockThread dieLockThread=new DieLockThread(false);
        Thread thread=new Thread(dieLockThread);
        thread.start();
        DieLockThread dieLockThread1=new DieLockThread(true);
        Thread thread1=new Thread(dieLockThread1);
        thread1.start();
    }
}

线程通信

多个线程相互牵制,相互调度,即线程间的相互作用

.wait一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器

.notify一旦执行此方法,就会唤醒被wait的一个线程。如果有多个线程被wait,就唤醒优先级高的那个

.notifyAll一旦执行此方法,就会唤醒所有被wait的线程

三者必须使用在同步代码块中,同步方法中

public class PrintNum implements Runnable {
    int i = 0;

    @Override
    public void run() {
        while (true) {
            synchronized (this) {
            this.notify();
            System.out.println(Thread.currentThread().getName() + ":" + i++);
                if (i > 100) {
                    break;
                }
                try {
                    this.wait();
                   //this.notify
                   //this.notifyAll
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

新增创建线程方式

实现Callable接口和Runnable相比,Callable功能更强大一些

Callable可以有返回值

方法可以抛出异常

支持泛型的返回值

需要借助FutureTask类,获得返回结果

public class Sum implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        int i = 0;
        for (int j = 0; j < 5; j++) {
            i += j;
        }
        return i;
    }
}
public class Test {
    public static void main(String[] args) {
        Sum sum = new Sum();
        FutureTask futureTask = new FutureTask(sum);
        Thread thread = new Thread(futureTask);
        thread.start();
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值