Java学习记录 多线程篇

线程

线程 是进程中的执行过程,一个进程包含有多个线程

进程 是一个运行的应用程序,每个进程都有自己独立的内存空间。在Windows系统中,一个运行的exe(应用程序)就是一个进程

实现线程

实现线程线程主要有 java.lang.Thread类Runnable接口

Thread类

Class Thread

java.lang.Object
java.lang.Thread

Thread类中实例化的对象代表线程,启动需要Thread实例

常用构造方法

Thread()

Thread(String name)

name: 自定义线程名

常用方法

修饰符 方法 说明
long getId() 返回线程标识符
String getName() 返回线程名称
int getPriority() 返回线程的优先级
Thread.State getState() 返回线程的状态
void interrupt() 中断线程
boolean isAlive() 线程是否运行
boolean isInterrupted() 线程是否被中断
void run() 调用该Runnable对象的run方法
void start() 线程开始执行run方法
void sleep(long ms) 线程以指定的毫秒数暂停(等待)
void join() 在线程中加入另一个线程
boolean interrupted() 中断线程
void setPriority(int newPriority) 设置线程的优先级newPriority的范围(1-10)
String toString() 返回线程的字符串表示、线程的名、优先级、线程组

例子:

public class Demo {
     
    public static void main(String[] args) {
     
        
        //实例对象
        Thread a = new MyThreadA();
        Thread b = new MyThreadB();
        
        /**其他方法测试*/
        System.out.println("==========");
        System.out.println("a.getId():"+a.getId());
        System.out.println("a.getName():"+a.getName());
        System.out.println("a.getPriority():"+a.getPriority());
        System.out.println("a.getState():"+a.getState());
        System.out.println("a.isAlive():"+a.isAlive());
        System.out.println("a.isInterrupted():"+a.isInterrupted());
        System.out.println("a.toString():"+a.toString());
        System.out.println("==========");
        
        //执行线程(双线程执行,同时执行)
        /**线程A*/
        a.start();
        /**线程B*/
        b.start();
        
        /**
         
        以下代码为运行a对象的run()方法再执行b对象run()方法
        a.run();
        b.run();
        
        */
        
    }
}

class MyThreadA extends Thread{
     
    @Override
    public void run() {
     
        for (int i = 0; i < 26; i++) {
     
            System.out.print("A:"+i);
            /**休眠1秒(等待)*/
            try {
     
                Thread.sleep(1000);
            } catch (InterruptedException e) {
     
                e.printStackTrace();
            }
        }
    }
    
}

class MyThreadB extends Thread{
     
    @Override
    public void run() {
     
        for (char i = 'a'; i < 'z'; i++) {
     
            System.out.println("B:"+i);
            /**休眠1秒(等待)*/
            try {
     
                Thread.sleep(1000);
            } catch (InterruptedException e) {
     
                e.printStackTrace();
            }
        }
    }
    
}



/**运行结果
==========
a.getId():13
a.getName():No.1
a.getPriority():5
a.getState():NEW
a.isAlive():false
a.isInterrupted():false
a.toString():Thread[No.1,5,main]
==========
 B:a
 A:0
 B:b
 A:1
 B:c
 A:2
 A:3
 B:d
 B:e
 A:4
 A:5
 B:f
 A:6
 B:g
 A:7
 B:h
 A:8
 B:i
 B:j
 A:9
 A:10
 B:k
 A:11
 B:l
 A:12
 B:m
 B:n
 A:13
 A:14
 B:o
 B:p
 A:15
 B:q
 A:16
 B:r
 A:17
 B:s
 A:18
 A:19
 B:t
 B:u
 A:20
 A:21
 B:v
 A:22
 B:w
 B:x
 A:23
 B:y
 A:24
 A:25
 
 */

Runnable接口

线程一般通过Thread类创建的。如果该类要实现进程且该类又继承了其他类(非Thread类),可以通过Runnable接口实现进程

Java学习记录 多线程篇_第1张图片

构造方法

Thread(Runnable target)

Thread(Runnable target , String name)

target: 启动线程时调用,run方法
name: 自定义线程名

例子:

import javax.swing.*;
import java.awt.*;

//继承JFrame类 且 实现Runnable接口
public class MyRunnable extends JFrame implements Runnable{
     
    
    private JLabel jl = null;
    private String str = "内容";
    
    public  MyRunnable(){
     
        //标题
        //setTitle("移动字体");
        super("移动字体");
        //窗体关闭模式
        setDefaultCloseOperation(3);
        //坐标大小
        setBounds(400,400,280,80);
        //获取窗体容器
        Container c = getContentPane();
        c.setLayout(null);
        jl = new JLabel(str);
        jl.setFont(new Font("微软雅黑",Font.PLAIN,20));
        jl.setBounds(10,0,50,40);
        c.add(jl);

        //可见
        setVisible(true);
    }
    
    @Override
    public void run() {
     
        //No.1改变字体内容实现移动 (空格
        //String tmp = "";
        //while (true){
     
        //    jl.setText(tmp+str);
        //    tmp += " ";
        //    //50空格清空
        //    if (tmp.length() > 50){
     
        //        tmp = "";
        //    }
        //    try {
     
        //        //等待 50毫秒
        //        Thread.sleep(50);
        //    } catch (InterruptedException e) {
     
        //        e.printStackTrace();
        //    }
        //}

        //No.2更改字体本身的位置 (坐标
        int count = 10 ;
        while(true){
     
            //更改坐标
            jl.setLocation(count++,0);
            if(count >= 250) {
     
                count = 10;
            }
            try {
     
                Thread.sleep(10);
            } catch (InterruptedException e) {
     
                e.printStackTrace();
            }
        }

    }
    
    public static void main(String[] args) {
     
        MyRunnable runnable = new MyRunnable();
        Thread t = new Thread(runnable);
        t.start();
    }
    
}

运行结果

线程生命周期

线程具有生命周期,有7种分别为:出生状态、就绪状态、运行状态、休眠状态、阻塞状态、死亡状态

周期的说明:

出生状态: 线程创建后到线程的start()方法前
就绪状态: 可执行状态,当线程获取系统资源就进入运行状态
运行状态: run()方法,没有意外线程则一直运行到结束
休眠状态: 执行sleep()方法休眠(等待)
阻塞状态: 等待用户 输入/输出 ,用户 输入/输出 结束后进入就绪状态
死亡状态: 线程的run()方法执行完毕,则进入死亡状态

Java学习记录 多线程篇_第2张图片

Windows操作系统中,会为每个线程分配一小段CPU时间片,一旦CPU时间片结束会切换到下一线程

再次进入运行状态:

  • 线程调用notify()方法
  • 线程调用notifyAll()方法
  • 线程调用interrupt()方法
  • 线程的休眠时间结束
  • 输入/输出 结束

操线程方法

线程休眠

sleep(long ms) 方法 线程休眠(暂停。它可能会抛出InterruptedException异常,所以放在try-catch块中。暂停后醒来,不能保证它能立即运行!

//休眠1s
Thread.sleep(1000); 

线程加入

join() 方法 加入线程。当一个线程执行中,join()方法可使另一个线程加入,线程需要等另一个线程执行完才可以继续执行原旧的线程!
join([long millis] [, int nanos])

millis: 等待另一个线程的时间(秒
**nanos: **另一个线程的死亡时间(纳秒

//加入ThreadB线程
··· run(){
       //线程执行中
    while(true){
     
        //加入另一个线程
        ThreadB.join();
    }
}

线程中断

interrupted() 方法 中断线程。 能使线程离开run()方法,同时结束线程,但会抛出InterruptedException异常!

//终止线程:ThreadA
ThreadA.interrupted();

线程礼让

yield()  方法 线程礼让,给当前运行状态的线程提个醒,告知它可以将资源礼让给其他线程。但目前情况没有机制能保证当前线程会礼让将资源分配!(操作系统会自动分配CPU时间片执行 (不常用

线程优先级

每个线程都有自己的优先级,线程的优先级代表着该线程的重要性。多个处于就绪的线程就能体现优先级的作用!

Thread类中包含成员变量代表有:
Thread.MAX_PRIORITY = 10 (常量10
Thread.MIN_PRIORITY = 1 (常量1
Thread.NORM_PRIORITY = 5 (默认5

setPriority(int newPriority) 方法 进程优先级调整。调整线程的优先级的情况newPriority范围(0-10)

import javax.swing.*;
import java.awt.*;

public class PriorityBookTest extends JFrame {
     

    private Container c = getContentPane();
    private JProgressBar
            jp1 = new JProgressBar(),
            jp2 = new JProgressBar(),
            jp3 = new JProgressBar(),
            jp4 = new JProgressBar();
    private Thread
            threadA = null,
            threadB = null,
            threadC = null,
            threadD = null;

    public PriorityBookTest(){
     
        super("线程优先级");
        setBounds(300 , 230 ,100,150);
        setLayout(new FlowLayout());
        setVisible(true);

        threadA = new Thread(newThread(c , jp1));
        threadB = new Thread(newThread(c , jp2));
        threadC = new Thread(newThread(c , jp3));
        threadD = new Thread(newThread(c , jp4));
        setPriority("A" , 10 , threadA);
        setPriority("B" , 7 , threadB);
        setPriority("C" , 4 , threadC);
        setPriority("D" , 1 , threadD);
    }

    private static Thread newThread(Container c , JProgressBar jp){
     
        c.add(jp);
        jp.setStringPainted(true);
        Thread thread = new Thread(new Runnable() {
     
            @Override
            public void run() {
     
                int count = 0 ;
                while (count <= 100){
     
                    jp.setValue(count++);
                    try {
     
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
     
                        e.printStackTrace();
                    }
                }
            }
        });
        return thread;
    }

    public static void setPriority(String threadName , int priority , Thread t){
     
        //设置进程优先级、名,启动
        t.setPriority(priority);
        t.setName(threadName);
        t.start();
    }

    public static void main(String[] args) {
     
        new PriorityBookTest();
    }
}

线程同步

多线程执行程序,会出现线程抢资源的现象,该现象会导致数据脏读!为了防止多线程的冲突,JAVA提供了线程同步的机制来防止资源抢占的问题!

synchronized关键字

synchronized关键字采用定时只允许一个线程访问共享资源 (道理跟上排队上厕所一样

同步块

每个对象都有标志位,它具有0和1两个值。0代表同步块中在运行其他线程;1代表该线程能被同步块执行,执行中途并将Object对象的标志位设置为0,防止其他线程执行同步块中的代码。(一个线程运行到同步块时首先检查该对象的标志位)

synchronized(Object){
     
    ···
}
//Object:任意对象,仅作为标志
public class ThreadSafeTestCodeBlock implements Runnable {
     

    //模拟售票系统 (同步代码块
    int count = 10; //票池

    @Override
    public void run() {
     
        //同步代码块
        synchronized(this) {
     
            while (true) {
     
                if (count > 0) {
     
                    //try {
     
                    //    Thread.sleep(1000);
                    //} catch (InterruptedException e) {
     
                    //    e.printStackTrace();
                    //}
                    //打印前休眠会导致数字存在负数
                    System.out.println(this.count--);
                    //打印后休眠可防止数字负数
                    try {
     
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
     
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public static void main(String[] args) {
     
        ThreadSafeTest t = new ThreadSafeTest();
        //5个线程 (5个售票处
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        Thread t3 = new Thread(t);
        Thread t4 = new Thread(t);
        Thread t5 = new Thread(t);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
    }
}

同步方法

在自定义方法 前面修饰 synchronized关键字 形成同步方法。
某对象调用同步方法时,该对象的其他同步方法必须等待该同步方法执行完毕后才能被执行。必须将每个能访问共享资源的方法修饰为synchronized,否则会报错!

synchronized void sell(){
     
    ···
}
public class ThreadSafeTest implements Runnable {
     

    //模拟售票系统 (同步方法
    int count = 10; //票池

    private synchronized void sell(){
     
        while (true) {
     
            if (count > 0) {
     
                //try {
     
                //    Thread.sleep(1000);
                //} catch (InterruptedException e) {
     
                //    e.printStackTrace();
                //}
                //打印前休眠会导致数字存在负数
                System.out.println(this.count--);
                //打印后休眠可防止数字负数
                try {
     
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
     
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public void run() {
     
        sell();
    }

    public static void main(String[] args) {
     
        ThreadSafeTest t = new ThreadSafeTest();
        //5个线程 (5个售票处
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        Thread t3 = new Thread(t);
        Thread t4 = new Thread(t);
        Thread t5 = new Thread(t);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
    }
}

你可能感兴趣的:(Java,学习记录,多线程,java)