0
点赞
收藏
分享

微信扫一扫

Java 线程

小安子啊 2022-03-12 阅读 39

线程

  • 程序、进程、线程

    程序(program):是为完成特定任务、用某种语言编写的一组指令的集合。

即指一端静态的代码。

    进程(process):指正在执行的程序,从Windows角度讲,进程是操作系统进行资源分配的最小单位。

    线程(thread):进程可进一步细化为线程,是一个进程内部的最小执行单元,是操作系统进行任务调度的最小单元,隶属于进程。

  • 线程和进程的关系

  • 创建线程

  1. 继承Thread类的方式(类就不能继承其他类);
    package Thread.Demo01;
    /*
        继承Thread类  类就不能继承其他类
     */
    public class MyThread extends Thread{
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println("MyThread:"+i);
            }
        }
    
        public static void main(String[] args) {
            //创建线程
            MyThread myThread = new MyThread();
                     myThread.start();
            System.out.println("结束");
        }
    }

    运行结果:

     结束
        MyThread:0
        MyThread:1
        MyThread:2
        MyThread:3
        MyThread:4
        MyThread:5
        MyThread:6
        MyThread:7
        MyThread:8
        MyThread:9

  2. 实现Runnable接口的方式(类还可以继承其他类);
    package Thread.Demo01;
    /*
        实现Thread接口  类还可以继承其他类
        重写run()
        这个类可以成为线程任务类
        Thread.currentThread() 获得当前正在执行的线程对象
    
     */
    public class ThreadDemo implements Runnable{
    
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println("ThreadDemo:"+i);
              //System.out.println(Thread.currentThread().getName();
    
            }
        }
    
        public static void main(String[] args) {
            //创建线程执行任务
            ThreadDemo threadDemo = new ThreadDemo();
           
            //创建线程
            Thread t = new Thread(threadDemo);
            //定义线程名称
            //Thread t = new Thread(threadDemo,"自定义线程");
            //启动线程
            t.start();
    
            for (int i = 0; i < 10; i++) {
                System.out.println("main:"+i);
            }
        }
    }

    运行结果:

     main:0
        main:1
        main:2
        ThreadDemo:0
        ThreadDemo:1
        ThreadDemo:2
        ThreadDemo:3
        ThreadDemo:4
        ThreadDemo:5
        ThreadDemo:6
        main:3
        ThreadDemo:7
        ThreadDemo:8
        ThreadDemo:9
        main:4
        main:5
        main:6
        main:7
        main:8
        main:9

  3. 继承方式和实现方式的联系和区别:
  4.   【区别】

      【实现Runnable的好处】

  5. 避免了单继承的局限性;
  6. 多个线程可以共享同一个接口实现类的对象,非常适合多个相同线程来处理同一份资源。

  • Thread类中的方法
  1. Thread类构造方法:
  1. 构造方法

    说明

    Thread()

    创建一个新的线程

    Thread(String name)

    创建一个指定名称的线程

    Thread(Runnable target)

    利用Runnable对象创建一个线程,启动时将执行该对象的run方法。

    Thread(Runnable target,String name)

    利用Runnable对象创建一个线程,并指定该线程的名称。

     2.Thread类常用方法:

Void start()

启动线程

Final void setName(String name)

设置线程的名称

Final String getName()

返回线程的名称

Final void setPriority(int newPriority)

设置线程的优先级

Final int getPriority()

返回线程的优先级

Final void join()

throws InterruptedException

等待线程终止

static Thread currentThread()

返回对当前正在执行的线程对象的引用

static void sleep(long millis)

throws InterruptedException

让当前正在执行的线程休眠(暂停执行)

休眠时间由millis(毫秒)指定

  • 线程优先级

  • 线程状态

 

 

线程的状态:

代码:
    package Thread.Demo02;

public class ThreadDemo extends Thread {
    
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
//            try {
//                //让线程休眠指定的时间
//                Thread.sleep(1000);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
            if (i%10==0){
                //线程让步
                Thread.yield();
            }
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }


    public static void main(String[] args) throws InterruptedException {
        ThreadDemo t = new ThreadDemo();
                   t.start();
                   //等待该线程结束(把其他线程加入到此线程,让其他线程阻塞)
                   t.join();

        for (int i = 0; i < 1000; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}

  • 线程的分类

守护线程:一直执行,必须在启动前设置,在所有的用户线程结束后自动结束,如垃圾回收线程;

用户线程

    

  • 多线程的概念
  1. 多线程:

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

  1. 何时需要多线程:
  1. 多线程的优点:
  1. 多线程的缺点:
  1. 多线程何时产生问题:多个线程,访问的是同一个共享资源(数据);
  2. 多个线程访问共享资源出现问题的本质在于CPU是多核的,理论上是可以同时执行多个线程。

  • 线程同步

并行:在同一个时间,同时做多个事情    

      例如:360同时做多件事情;

并发:在一段时间内,依次做多件事情      并发执行,交替执行;

多线程同步:线程排队 + 锁

      确保一个时间点只有一个线程访问共享资源,可以给共享资源加一把锁,哪个线程获取了这把锁,才有权访问该资源。

每个类被加载到内存中时,都会为该类创建一个class类对象,用于封装类的信息,一个类即使创建多个对象,class类的对象只有一个;

案例:买票机制

package Thread.Demo03;
/*
  模拟买票线程
 */
public class TicketThread extends Thread{

    //10张票   加static表示共享资源,只有一份
    static int num = 10;
    static Object lockFlog = new Object();

    @Override
    public void run() {
        while (true) {

            /*
            if(num > 0) {
                try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
                 */

            /*
                synchronized(锁对象) {
                    同步代码
                }
                锁对象可以是任何对象,但是对于多个线程必须是同一个.
                在对象中,有一个对象头的区域,在对象头中有一个标志为(锁状态)
                具体实现,由编译后的指令实现控制
             */

            synchronized (lockFlog) {
                if (num > 0) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                        System.out.println(Thread.currentThread().getName() + ":" + num);
                        num--;
                    } else{
                        break;
                    }
                }
            }
        }

    public static void main(String[] args) {
        TicketThread t1 = new TicketThread();
                     t1.setName("窗口1");
        TicketThread t2 = new TicketThread();
                     t2.setName("窗口2");

                     t1.start();
                     t2.start();
    }
}

运行结果:

运行结果:
窗口1:10
窗口1:9
窗口1:8
窗口1:7
窗口1:6
窗口1:5
窗口1:4
窗口1:3
窗口1:2
窗口2:1

加锁后:

加锁后:
package Thread.Demo03;

public class TicketThread_back {

    //10张票   加static表示共享资源,只有一份
    static int num = 10;
    static Object lockFlog = new Object();

    public void run() {
        while (true) {

                if (num > 0) {
                    break;
                }
                print();
            }
        }

    public static void main(String[] args) {
        TicketThread t1 = new TicketThread();
        t1.setName("窗口1");
        TicketThread t2 = new TicketThread();
        t2.setName("窗口2");

        t1.start();
        t2.start();
    }

    /*
        synchronized修饰方法时,并没有显示的让我们添加锁的标志对象。
        在修饰非静态方法时,锁标志的对象默认this
        在修饰静态方法时,锁标志对象是class类对象
     */
    public synchronized void print() {
        if (num > 0) {
            try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
              System.out.println(Thread.currentThread().getName() + ":" + num);
              num--;
            }
        }
}

运行结果:

窗口1:10
窗口2:9
窗口2:8
窗口2:7
窗口2:6
窗口2:5
窗口2:4
窗口2:3
窗口2:2
窗口2:1
  • Lock锁

1.java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象。

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

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

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

package Thread.Demo04;
/*
    线程死锁
    同步代码块中死循环,锁一直释放不了
    同步代码块嵌套,不同线程一直占着对方需要的同步锁不释放
 */
public class ThreadDemo extends Thread {

    static Object obja = new Object();
    static Object objb = new Object();
    boolean flag = true;

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

    @Override
    public void run() {

        if (flag) {
            synchronized (obja) {
                System.out.println("if obja");
                synchronized (objb) {
                    System.out.println("if objb");
                }
            }
        } else {
            synchronized (objb) {
                System.out.println("else objb");
                synchronized (obja) {
                    System.out.println("else obja");
                }
            }

        }
    }

    public static void main(String[] args) {
        ThreadDemo d1 = new ThreadDemo(true);
        d1.start();

        ThreadDemo d2 = new ThreadDemo(false);
        d2.start();
    }

}

多次运行结果:

首次运行:
if obja
if objb
else objb
else obja

二次运行:
else objb
else obja
if obja
if objb

三次运行:
if obja
else objb
(后不再改变)

  • 线程通信

线程通讯:多个线程通过相互牵制,相互调度,即线程间的相互作用。

三个方法:

  • 新增创建线程方式

实现Callable接口与使用Runnable相比,Callable功能更加强大;

package Thread.Demo07;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class SumThread implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        int num = 0;
        for (int i = 0; i < 100; i++) {
            num += i;
        }
        return num;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        SumThread sumThread = new SumThread();
        FutureTask<Integer> futureTask = new FutureTask(sumThread);

        Thread t = new Thread(futureTask);
               t.start();

               //获取返回值
               Integer sum = futureTask.get();
               System.out.println(sum);
    }
}

运行结果:4950

举报

相关推荐

0 条评论