线程Thread(2)

1. 线程的并发(Concurrent)

synchronized (同步关键字)

语法

synchronized(对象) {
    要作为原子操作代码}

用synchronized 解决并发问题:

static int i = 0;
static Object obj = new Object(); // 房间,能容纳一个人

public static void main(String[] args) throws InterruptedException {
    Thread t1 = new Thread(() -> { // 甲
        for (int j = 0; j < 5000; j++) {
            synchronized (obj) { // 甲会锁住这个房间
                i++;
            } // 甲从房间出来解开了锁
        }
    });

    Thread t2 = new Thread(() -> { // 乙
        for (int j = 0; j < 5000; j++) {
            synchronized (obj) { // 乙   在门外等待
                i--;
            } //
        }
    });
    t1.start();
    t2.start();

    t1.join();
    t2.join();
    System.out.println(i);
}

每个对象都有一个自己的monitor(监视器),当一个线程调用synchronized(对象),就相当于进入了这个对象的监视器。要检查有没有owner,如果没有,此线程成为owner; 但如果已经有owner了,这个线程在entryset的区域等待owner的位置空出来。

成为owner可以理解为获得了对象的锁

在竞争的时候,是非公平的

synchronized必须是进入同一个对象的monitor 才有上述的效果
这里写图片描述

2. volatile 易变的

可以用来修饰成员变量和静态成员变量,他可以防止线程从自己的高速缓存中查找变量的值,必须到主存中获取它的值。
它保证的是变量在多个线程之间的可见性, 不能保证原子性

static boolean run = true;

public static void main(String[] args) throws InterruptedException {
    Thread t = new Thread(()->{
        while(run){
            // ....
        }
    });
    t.start();

    Thread.sleep(1000);
    run = false;
}

一个线程对run变量的修改对于另一个线程不可见,导致了另一个线程无法停止
synchronized 语句块既可以保证代码块的原子性,也可以保证代码块内变量的可见性。但缺点是synchronized是属于重量级操作,性能会受到影响。

 //要解决上述线程无法停止的问题只需给static boolean run =true;前面加入volatile修饰符,或使用Synchronized.
 volatile static boolean run = true;

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
            while(run){
                // ....
            }
        });
        t.start();

        Thread.sleep(1000);
        run = false;
    }
   volatile static boolean run = true;
     static Object obj=new Object();
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
            synchronized (obj){
            while(run){
                // ....
                }
            }
        });
        t.start();

        Thread.sleep(1000);
        run = false;
    }

3. synchronized的另外两种写法

public synchronized void test() {

}
等价于
public void test() {
    synchronized(this) {

    }
}

方法参数前加synchronized,相当于修饰的是这个方法,谁调用的这个方法则锁住的就是调用这个方法的对象.

class Test{
    public synchronized static void test() {

    }
}
等价于
public static void test() {
    synchronized(Test.class) {

    }
}

方法参数前加synchronized static,相当于修饰的是这个类,谁调用的这个方法则给他提供一个这个类的监视器,就是使用这个类的锁
例题:情况5:

class Number{
    public synchronized static void a() {
        try { Thread.sleep(1000); } catch (InterruptedException e) {}
        System.out.println(1);
    }
    public synchronized void b() {
        System.out.println(2);
    }
}
public static void main(String[] args) {
    Number n1 = new Number();
    new Thread(()->{ n1.a(); }).start();
    new Thread(()->{ n1.b(); }).start();
}//2
//1

情况6:

class Number{
    public synchronized static void a() {
        try { Thread.sleep(1000); } catch (InterruptedException e) {}
        System.out.println(1);
    }
    public synchronized static void b() {
        System.out.println(2);
    }
}
public static void main(String[] args) {
    Number n1 = new Number();
    new Thread(()->{ n1.a(); }).start();
    new Thread(()->{ n1.b(); }).start();
}//1
//2

情况7:

class Number{
    public synchronized static void a() {
        try { Thread.sleep(1000); } catch (InterruptedException e) {}
        System.out.println(1);
    }
    public synchronized void b() {
        System.out.println(2);
    }
}
public static void main(String[] args) {
    Number n1 = new Number();
    Number n2 = new Number();
    new Thread(()->{ n1.a(); }).start();
    new Thread(()->{ n2.b(); }).start();
}//2
//1

情况8:

class Number{
    public synchronized static void a() {
        try { Thread.sleep(1000); } catch (InterruptedException e) {}
        System.out.println(1);
    }
    public synchronized static void b() {
        System.out.println(2);
    }
}
public static void main(String[] args) {
    Number n1 = new Number();
    Number n2 = new Number();
    new Thread(()->{ n1.a(); }).start();
    new Thread(()->{ n2.b(); }).start();
}//1
//2

4. 线程死锁

a 线程 获得 A 对象 锁
接下来获取B对象的锁
b 线程获得 B对象 锁
接下来获取A对象的锁
例:

Object A = new Object();
Object B = new Object();


Thread a = new Thread(()->{
    synchronized (A) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (B) {
            System.out.println("操作...");
        }
    }
});

Thread b = new Thread(()->{
    synchronized (B) {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (A) {
            System.out.println("操作...");
        }
    }
});
a.start();
b.start();

检测死锁可以使用 jconsole工具

5. 线程的状态

NEW(新建) 线程刚被创建,但是还没有调用 start方法

RUNNABLE(可运行) 当调用了start() 方法之后

BLOCKED(阻塞) 当线程进入了monitor监视器区,处于entrySet里准备竞争锁的时候,处于阻塞状态

WAITING(等待) 当调用了对象的wait方法,或调用了线程对象的join方法,进入了WaitSet,处于等待状态

TIMED_WAITING 当调用wait(long n) join(long n) 进入了WaitSet,处于有限时的等待状态
当调用sleep(long n) 是让当前线程放弃cpu的时间片,睡眠一会

TERMINATED (终止)当线程代码运行结束

五种状态:
NEW(新建), RUNNABLE(可运行) , RUNNING(正在运行), 阻塞(BLOCKED,WAITING, TIMED_WAITING )TERMINATED(终止)

6. 如何让两个线程以固定的顺序运行

static Object obj = new Object();
static boolean t2runed = false;// t2是否执行过
// 打印 2, 1

public static void main(String[] args) {

    Thread t1 = new Thread(() -> {
        synchronized (obj) {
            while(!t2runed) { // 如果t2没有执行过
                try {
                    obj.wait(); // 线程t1 先等一会
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println(1);
    });

    Thread t2 = new Thread(()->{
        System.out.println(2);
        synchronized (obj) {
            t2runed = true;
            obj.notify();
        }
    });

    t1.start();
    t2.start();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一个基于 RT-Thread 操作系统的多线程应用程序设计问题。以下是代码实现: ```c #include <rtthread.h> /* 定义线程栈和控制块 */ #define THREAD_STACK_SIZE 512 ALIGN(RT_ALIGN_SIZE) static rt_uint8_t thread1_stack[THREAD_STACK_SIZE]; static struct rt_thread thread1; ALIGN(RT_ALIGN_SIZE) static rt_uint8_t thread2_stack[THREAD_STACK_SIZE]; static struct rt_thread thread2; ALIGN(RT_ALIGN_SIZE) static rt_uint8_t thread3_stack[THREAD_STACK_SIZE]; static struct rt_thread thread3; /* 定义线程优先级 */ #define THREAD1_PRIORITY 25 #define THREAD2_PRIORITY 24 #define THREAD3_PRIORITY 23 /* 定义线程函数 */ void thread1_entry(void* parameter) { while(1) { rt_thread_mdelay(1000); /* 每隔1秒执行一次 */ } } void thread2_entry(void* parameter) { /* 执行完毕一段程序后自动被系统脱离 */ rt_kprintf("Thread2 is running.\n"); } void thread3_entry(void* parameter) { rt_tick_t last_tick = 0; rt_tick_t current_tick = 0; rt_uint8_t flag = 0; while(1) { /* 实现一个周期为10个OSTicks的方波 */ current_tick = rt_tick_get(); if(current_tick - last_tick >= 10) { last_tick = current_tick; if(flag) { flag = 0; } else { flag = 1; } rt_pin_write(LED1_PIN, flag); } } } /* 应用程序入口 */ int main(void) { /* 初始化 LED 引脚 */ rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT); rt_pin_write(LED1_PIN, PIN_LOW); /* 动态创建线程1 */ rt_thread_init(&thread1, "thread1", thread1_entry, RT_NULL, &thread1_stack[0], sizeof(thread1_stack), THREAD1_PRIORITY, /* 优先级为25 */ 20); rt_thread_startup(&thread1); /* 静态创建线程2 */ rt_thread_bind(&thread2, "thread2", thread2_entry, RT_NULL, &thread2_stack[0], sizeof(thread2_stack), THREAD2_PRIORITY); /* 优先级为24 */ rt_thread_startup(&thread2); /* 静态创建线程3 */ rt_thread_bind(&thread3, "thread3", thread3_entry, RT_NULL, &thread3_stack[0], sizeof(thread3_stack), THREAD3_PRIORITY); /* 优先级为23 */ rt_thread_startup(&thread3); return 0; } ``` 在代码中,我们使用了 RT-Thread 操作系统提供的动态创建线程和静态创建线程的两种方式。线程1被动态创建,而线程2和线程3被静态创建。线程1的优先级为25,线程2的优先级为24,线程3的优先级为23。线程2会执行完毕一段程序后自动被系统脱离。线程1被设计成死循环,循环中有让出 CPU 使用权的动作 - 使用了 delay 函数,该线程在线程2退出运行之后开始运行,并且每隔1秒运行一次。线程3实现一个周期为10个OSTicks的方波。我们在主函数中进行了线程的初始化和启动,并初始化了 LED 引脚。通过设置虚拟逻辑分析仪,可以获取到线程1和线程2的状态信息。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值