Java——多线程与并发

标题

多线程与并发

1.进程与线程
(1)什么是进程与线程?
进程:它是程序在处理机上的一次执行过程,是一个动态的概念。
进程是一个具有一定独立功能的程序,一个实体,每一个进程都有自己的地址空间。
进程的三种基本状态:Ready(就绪状态),Running(运行状态),Blocked(阻塞状态)。
线程:是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行,一个进程至少有一个线程。

(2)并发与并行的区别
并行:就是两个任务同时运行。
并发:就是两个任务同时请求运行,但是处理器一次只能接受一个任务,就会把两个任务安排轮流进行,由于CPU时间片运行的时间较短,就会感觉两个任务在同时运行。

2.线程实现的两种基本方式
(1) 第一种是通过继承Thread类

class Mythread extends Thread{
    @Override
    public void run() {
    //逻辑处理
    }
}
Mythread mt = new Mythread();
mt.start(); //启动线程

(2)第二种是通过实现Runnable接口

class Mythread implements Runnable{
    @Override
    public void run() {
    //逻辑处理
    }
}
Mythread mt = new Mythread();
Thread t = new Thread(mt);
t.start(); //启动线程

一般比较常用的是第二种方法,更加灵活一些。

3.join与中断线程
public final void join() throw InterruptedException
等待这个线程任务执行完毕。
InterruptedException —— 如果任何线程中断当前线程。当抛出此异常时,当前线程的中断状态将被清除。

(1)public void interrupt()
中断这个线程。

(2)自定义中断线程
通过定义个boolean类型的变量来控制线程的中断
话不多说,直接上代码

public class ThreadDemo {
                    public static void main(String[] args) {
                        MyRunable mr = new MyRunable();
                        Thread t= new Thread(mr);
                        t.start();//启动线程
                        for (int i = 0; i <50 ; i++) {
                            System.out.println(Thread.currentThread().getName() +"--"+i);
                            try {
                                Thread.sleep(300);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            if (i == 20) {
                                mr.flag =false;//当i=20时,中断线程
            }
        }
    }
}

class MyRunable implements Runnable{
    public boolean flag = true;
    public MyRunable(){
        flag = true;
    }
    @Override
    public void run() {
        int i =0;
        while(flag){
            System.out.println(Thread.currentThread().getName()+"======="+(i++));
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

4.线程的同步
在多线程的操作中,多个线程有可能同时处理同一个资源。而解决数据共享问题,必须使用同步,同步就是指 多个线程在同一个时间段内只能有一个线程执行指定的代码,其他线程要等待当前线程完毕后才能继续执行。
线程同步有以下三种方法:
(1)同步代码块
synchronized(要同步的对象){
要进行的操作;
}
下面我用代码来模拟4个窗口来卖100张票的实例

public class ThreadDemo2 {
    public static void main(String[] args) {
        MyRunnable2 mr2 = new MyRunnable2();

        Thread t1 = new Thread(mr2);
        Thread t2 = new Thread(mr2);
        Thread t3 = new Thread(mr2);
        Thread t4 = new Thread(mr2);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

class MyRunnable2 implements Runnable{

    private int ticket = 100;//票数
    @Override
    public void run() {
        for (int i = 0; i < 300; i++) {
            if(ticket > 0){
                 synchronized (this) {
                    ticket--;
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("您购买的票剩余" + ticket + "张");
                }
            }
        }
    }
}

(2)通过同步方法
public synchronized void method(){
要进行的操作;
}
在上面的代码实例中,线程的共享资源是卖票,故只需要在MyRunnable2里写一个同步方法,还是直接附上代码。

//同步方法
    private synchronized void method(){
        if (ticket > 0){
                            ticket--;
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("您购买的票剩余" + ticket + "张");
        }
    }

写好之后,只需要在for循环里直接调用同步方法,即可实现线程同步。
(3)使用Lock (ReentrantLock)
Lock实现提供比使用Synchronized方法和语句可以获得的更广泛的锁定操作。它们允许更灵活的结构化,可能具有完全不同的属性,而且可以支持多个相关联的对象Conditon。
下面是我根据上面的同步方法进行修改的代码。

ReentrantLock lock = new ReentrantLock();//互斥锁
//通过Lock实现同步
    private void method2(){
        lock.lock();
        try{
            if (ticket > 0){
                ticket--;
                try {
                      Thread.sleep(500);
                    } catch (InterruptedException e) {
                         e.printStackTrace();
                    }
                    System.out.println("您购买的票剩余" + ticket + "张");
            }
        }finally{
            lock.unlock();//释放锁
        }                 //加上try-finally语句保证锁一定会释放,避免死锁问题。
    }

5.死锁
过多的同步有可能出现死锁,死锁的操作一般是在程序运行的时候才有可能出现。还是直接上代码。

public class DeadThreadDemo{

    public static void main(String[] args){
        new DeadThread();
    }
}
//顾客
class Customer{
    public synchronized void say(Waiter w){
        System.out.println("顾客说:先吃饭再买单!");
        w.doService();
    }

    public synchronized void doService(){
        System.out.println("同意了,买完单再吃饭!");
    }
}
//服务员
class Waiter{
    public synchronized void say(Customer c){
        System.out.println("服务员说:先买单再吃饭!");
        w.doService();
    }
    public synchronized void doService(){
        System.out.println("同意了,吃完饭再买单!");
    }
}

//死锁
class DeadThread implements Runnable{
    Customer c = new Customer();
    Waiter   w = new Waiter();
    public DeadThread(){
        new Thread(this).start();
        w.say(c);
    }
    public void run(){
        c.say(w);
    }
}

运行之后即会发现,就会程序就会停住。原因是在同步方法中调用了另一个对象的同步方法,可能产生死锁。

6.线程池
线程池是预先创建线程的一种技术。线程池在还没有任务到来之前,创建一定数量的线程,放入空闲队列中,然后对这些资源进行复用。减少频繁的创建和销毁对象。

java里面的线程池接口是Executor,是一个执行线程的工具。

线程池接口是ExecutorService。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值