JAVA多线程

Posted redo19990701

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA多线程相关的知识,希望对你有一定的参考价值。

多线程概述

多线程是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。

多线程实现

1.继承Thread

自定义类继承Thread类,重写其中的run()方法(即写入想让该线程执行的代码),在main()函数中创建该类,并调用start()方法就会启动多线程并执行run()中的代码

class MyThread extends Thread
    private String greeting;
    MyThread(String s)
        greeting=s;
    

    @Override
    public void run() 
        while (true)
        System.out.println(greeting);
    

public class ThreadTest 
    public static void main(String[] args)
        MyThread ms1=new MyThread("haha");
        MyThread ms2=new MyThread("ahah");
        ms1.start();
        ms2.start();
    

2.实现Runnable接口

自定义类实现Runnable接口并且重写run()方法(即写入想让该线程执行的代码)

创建自定义类对象,再以该对象为参数创建Thread对象,最后使用Thread对象调用start()方法,即多线程完成启动

class MyThread implements Runnable
    private String greeting;
    MyThread(String s)
        greeting=s;
    

    @Override
    public void run() 
        while(true)
        System.out.println(greeting);
    

public class ThreadTest 
    public static void main(String[] args)
        MyThread ms1=new MyThread("haha");
        MyThread ms2=new MyThread("ahah");
        new Thread(ms1).start();
        new Thread(ms2).start();
    

两种方式对比

  1. 继承Thread
    • 好处:可以直接使用Thread类中的方法,代码简单
    • 弊端:如果已经有了父类,就不能用这种方法
  2. 实现Runnable接口
    • 好处:即使自己定义的线程类有了父类也可以,因为有了父类也可以实现接口,而且接口是可以多实现的
    • 弊端:不能直接使用Thread中的方法需要先获取到线程对象后,才能得到Thread的方法,代码复杂

匿名内部类写法

  1. 继承Thread类
public class ThreadTest 
    public static void main(String[] args)
        new Thread()
            @Override
            public void run() 
                while (true)
                    System.out.println("haha");
            
        .start();
    
  1. 实现Runnable接口
public class ThreadTest 
    public static void main(String[] args)
        new Thread(new Runnable() 
            @Override
            public void run() 
                while (true)
                    System.out.println("haha");
            
        ).start();
    

Thread方法

设置和获取线程名

//构造Thread时设置线程名
Thread(Runnable target, String name) 
//分配一个新的 Thread对象。  
Thread(String name) 
//分配一个新的 Thread对象。  
    
void setName(String name) 
//将此线程的名称更改为等于参数 name 。     
    
String getName() 
//返回此线程的名称。  

获取当前线程的对象

static Thread currentThread() 
//返回对当前正在执行的线程对象的引用。 

休眠,等待与唤醒线程

static void sleep(long millis) 
//使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性。
void wait() 
//导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法。 
void notify() 
//唤醒正在等待对象监视器的单个线程。  
void notifyAll() 
//唤醒正在等待对象监视器的所有线程。 

标记守护线程

守护线程又称后台线程,服务线程.普通线程在执行结束后停止,而守护线程服务于普通线程,当普通线程都停止守护进程也立即停止(服务对象消失)

void setDaemon(boolean on) 
//将此线程标记为 daemon线程或用户线程。 
class MyThread extends Thread
    private long last;
    MyThread(long last)//休眠时间
        this.last=last;
    

    @Override
    public void run() //休眠last秒然后打印该线程名
        try 
            sleep(last);
         catch (InterruptedException e) 
            e.printStackTrace();
        
        System.out.println(this.getName());
    

public class ThreadTest 
    public static void main(String[] args) throws InterruptedException 
        MyThread ms1=new MyThread(1000);//守护线程持续时间短
        ms1.setName("Daemon thread");
        MyThread ms2=new MyThread(4000);
        ms2.setName("Normal thread");
        ms1.setDaemon(true);
        ms1.start();
        ms2.start();
    

//输出结果
//Daemon thread
//Normal thread
//如果将main中的代码改为以下
MyThread ms1=new MyThread(4000);//守护线程持续时间长
ms1.setName("Daemon thread");
MyThread ms2=new MyThread(1000);
ms2.setName("Normal thread");
ms1.setDaemon(true);
ms1.start();
ms2.start();
//输出结果
//Normal thread
//由于普通线程早于守护线程停止,守护线程也被迫停止(没来得及运行)

加入线程

void join() 
//等待这个线程死亡。  
void join(long millis) 
//等待这个线程死亡最多 millis毫秒。 
class MyThread extends Thread
    private long last;
    MyThread(long last)//休眠时间
        this.last=last;
    

    @Override
    public void run() //休眠last秒然后打印该线程名
        try 
            sleep(last);
         catch (InterruptedException e) 
            e.printStackTrace();
        
        System.out.println(this.getName());
    

public class ThreadTest 
    public static void main(String[] args) throws InterruptedException 
        MyThread ms1=new MyThread(1000);//守护线程持续时间短
        ms1.setName("first");
        MyThread ms2=new MyThread(4000);
        ms2.setName("second");
        ms2.start();
        ms2.join();//加入线程
        ms1.start();
    

//线程1的睡眠时间短本应线程1先输出,但由于线程1执行前调用了线程1的join(),
//该函数会等待线程1停止才继续下面的代码
//所以输出
//second
//first

代码同步

当需要一段事务代码需要连续执行而不允许因为多线程的CPU调度在执行过程中切换线程,这样就需要代码同步达到这个要求

同步后的代码不会在执行过程中发生中断,也就是说CPU必须一口气执行完毕

同步代码块

  • 同步代码块即使用synchronized关键字加上一个锁对象来定义一段代码

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

    public class ThreadTest 
        public static void main(String[] args)
            Object o=new Object();
            new Thread()
                @Override
                public void run() 
                    while (true) 
                        synchronized (o) //锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,不能用匿名对象
                            for (int i = 0; i < 10; i++) 
                                System.out.print(i);
                            
                            System.out.println();
                        
                    
                
            .start();
            new Thread()
                @Override
                public void run() 
                    while (true) 
                        synchronized (o) 
                            for (int i = 0; i < 10; i++) 
                                System.out.print(i);
                            
                            System.out.println();
                        
                    
                
            .start();
        
    
    //如果不加synchronized那么打印出来的的不一定每一行都是0123456789

同步方法

  • 静态方法同步锁对象是当前类的字节码对象
  • 非静态同步方法锁对象是this
public static synchronized void printNum()     
    //使用synchronized关键字修饰的方法中所有的代码都是同步的
    for(int i=0;i<10;i++)
        System.out.println();

Timer(计时器)

  • 对任务进行定时规划运行
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class ThreadTest 
    public static void main(String[] args) throws InterruptedException 
        Timer t = new Timer();
        t.schedule(new MyTimerTask(), new Date(),3000);//三秒打印一次O(∩_∩)O
        while(true) 
            System.out.println(new Date());//每秒打印一次时间
            Thread.sleep(1000);
        
    

class MyTimerTask extends TimerTask 
    @Override
    public void run() 
        System.out.println("O(∩_∩)O");
    

以上是关于JAVA多线程的主要内容,如果未能解决你的问题,请参考以下文章

什么是JAVA的多线程?

Java多线程 1.认识Java线程

Java多线程 5.栅栏

java 如何实现多线程

java中啥叫做线程?啥叫多线程?多线程的特点是啥

Java多线程-Java多线程概述