【Java语法基础】11.多线程与锁

11.多线程与锁

多线程

写法1:类
  • 继承自Thread
package org.example;
class Worker extends Thread{
    @Override
    public void run()
    {
        for(int i = 0; i < 10; i ++)
        {
            System.out.println("Hello: " + this.getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

public class Main {
    public static void main(String[] args)  {

        Worker w1 = new Worker();
        Worker w2 = new Worker();

        w1.setName("Thread-1");
        w2.setName("Thread-2");

        w1.start();
        w2.start();
        //若要等待w1线程结束再执行下面的代码
        w1.join();
        w2.join();
        System.out.println("Main is over~");
    }
}
写法2:接口
  • 实现Runnable接口

这种写法可以使用同一个Worker的实例分别实现两个线程,天然地便于同步的实现

package org.example;
import java.sql.SQLOutput;

class Worker implements Runnable{

    @Override
    public void run()
    {
        for(int i = 0; i < 10; i ++)
        {
            System.out.println("Hello : " + i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Worker w = new Worker();
        new Thread(w).start();
        new Thread(w).start();

        Thread.sleep(1000);
        System.out.println("Main is over~");
    }
}
常见的API
  • start():开启一个线程
  • Thread.sleep():休眠一个线程
  • join():等待线程结束
  • interrupt():将休眠中的线程结束
  • setDaemon():将线程设置为守护线程,

守护线程:当该线程成为最后一个运行的线程时,操作系统会强制结束它。

如:

package org.example;
class Worker extends Thread{
    @Override
    public void run()
    {
        for(int i = 0; i < 10; i ++)
        {
            System.out.println("Hello: " + i + " " + this.getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                //休眠中检测到interrupt调用
                System.out.println("Be interrupted!");
            }
        }
    }
}

public class Main {
    public static void main(String[] args) throws InterruptedException {

        Worker w1 = new Worker();
        Worker w2 = new Worker();

        w1.setName("Thread-1");
        w2.setName("Thread-2");

        w1.start();
        w2.start();
        w1.join(5000);   //参数5000:最多等待5000ms
        w1.interrupt();

        System.out.println("Main is over~");
    }
}

又如:

package org.example;
class Worker extends Thread{
    @Override
    public void run()
    {
        for(int i = 0; i < 10; i ++)
        {
            System.out.println("Hello: " + i + " " + this.getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                //休眠中检测到interrupt调用
                System.out.println("Be interrupted!");
            }
        }
    }
}

public class Main {
    public static void main(String[] args) throws InterruptedException {

        Worker w1 = new Worker();
        Worker w2 = new Worker();

        w1.setName("Thread-1");
        w2.setName("Thread-2");
        
        //设置为守护线程
        w1.setDaemon(true);
        w2.setDaemon(true);

        w1.start();
        w2.start();
        Thread.sleep(5000);
        System.out.println("Main is over~");
    }
}

w1w2被设置为守护线程,当主线程执行结束后w1w2虽未结束却也被操作系统强行结束。

不同的线程竞争同一个资源可能造成读写冲突,为了解决这个问题,引入锁。

package org.example;
import java.util.concurrent.locks.ReentrantLock;

class Worker extends Thread{
    public static int cnt = 0; //互斥资源
    private static final ReentrantLock lock = new ReentrantLock();  //锁
    @Override
    public void run()
    {
        for(int i = 0; i < 200000; i ++)
        {
            lock.lock();  //获取cnt前先获取锁
            try
            {
                cnt ++;
            }
            finally {
                //无论如何cnt++后释放锁
                lock.unlock();
            }
        }
    }
}

public class Main {
    public static void main(String[] args) throws InterruptedException {

        Worker w1 = new Worker();
        Worker w2 = new Worker();

        w1.setName("Thread-1");
        w2.setName("Thread-2");
        w1.start();
        w2.start();
        w1.join();
        w2.join();

        System.out.println(Worker.cnt);
    }
}
写法1:类

Synchronized加到代码块上:

package org.example;
class Count
{
    public int cnt = 0;
}

class Worker extends Thread{
    public final static Count count = new Count();

    @Override
    public void run()
    {
        //给count加锁,注意synchronized只能作用于对象
        synchronized(count)
        {
            for(int i = 0; i < 200000; i ++)
                count.cnt ++;
        }
    }
}

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Worker();
        Thread t2 = new Worker();

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

        t1.join();
        t2.join();
        //输出最后的cnt
        System.out.println(Worker.count.cnt);

    }
}
写法2:接口

使用接口创建类,使用类对象创建Thread类,这样Thread的变量本身就互斥。

package org.example;

class Worker implements Runnable{
    public static int cnt = 0;
    @Override
    public synchronized void run()
    {
        for(int i = 0; i < 200000; i ++)
            cnt ++;
    }
    //上面对函数加同步,等价于对该类对象的this加锁
    //即:synchronized(this){ 临界区代码 }
}

public class Main {
    public static void main(String[] args) throws InterruptedException {

        Worker w = new Worker();
        //t1, t2采用同一个Worker对象构造Thread对象
        Thread t1 = new Thread(w);
        Thread t2 = new Thread(w);

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

        t1.join();
        t2.join();

        System.out.println(Worker.cnt);
    }
}

wait与notify

  • wait():将当前线程挂起,可加参数,代表最多挂起多少时间(单位是毫秒);

调用方式示例:

synchronized(a)
{
    a.wait(4000);  //挂起4000ms等待被唤醒
}
  • notify():随机唤醒一个线程;
  • notifyAll():唤醒所有线程;

以下实现一个例子:初始化5个线程,然后再初始化另一个线程,用它去唤醒前面的5个线程。

package org.example;

class Worker extends Thread
{
    public final Object object;
    public final boolean needWait;

    Worker(Object object, boolean needWait)
    {
        this.object = object;
        this.needWait = needWait;
    }
    
    @Override
    public void run()
    {
        synchronized (object)
        {
            try {
                if(needWait)
                {
                    object.wait();
                    System.out.println(this.getName() + " 被唤醒了!");
                }
                else
                {
                    //唤醒所有线程
                    object.notifyAll();
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

public class Main {
    public static void main(String[] args) throws InterruptedException {

        Object ob = new Object();

        for(int i = 0; i < 5; i ++)
        {
            Worker w = new Worker(ob, true);
            w.setName("Thread-" + i);
            w.start();
        }

        Worker w = new Worker(ob, false);
        w.start();
        
        Thread.sleep(2000);
    }
}
  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

指针常量

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值