Thread、Runnable、Callable、Future、线程状态、线程通信、synchronized、Lock、重入锁、读写锁

Thread、Runnable
好久没看线程和锁的东西,今天回来复习一下关于线程和锁的一些相关知识,感觉这里很重要。下期准备去复习Connection集合。直接进入主题。线程和进程声明关系,简单对线程进行一个简单概括。
说线程就先提下进程,进程是一个内存中的运行程序,每一个进程都有一个独立的空间,一个应用层序可以有多个进程,进程是应用程序的一次执行过程,系统运行一个程序就是一个程序从创建、运行、消亡的过程。 线程就是指进程的执行单元,是系统的执行单元,一个进程可以有多个线程,至少一个线程,可以多个。直接进入主题;
线程创建的三个方法:Thread、Runnable、Callable,第三种先不说 ,先复习下前两个,继承类Thread和实现Runnable接口,重写run方法然后调用实现类,不管哪种创建线程的方式,都记得启动线程的时候是调用start()方法,不是调用run方法就行。
这里提一下之前的Runnable相对于Thread 的优势,建立线程建议使用Runnabl接口:1,适合多个相同代码使用一个共享资源,2.避免单继承局限性,3.增强代码的健壮性,实现解耦,代码可以被多个线程继承,代码和线程独立,4.线程池只能被Runnable和Callable,不能被Thread类。
Thread和Runnable这里不多解释,上次也只是说了这些,直接从Callable开始,

Callable接口’:可调用的接口
方法:
public interface Callable{
public call throws Exception;
}
与jdk1.5之后加入,与Runnable接口一昂,实现之后代表一个线程任务,Callable接口具有泛型和抛出异常

Runnable和Callable的区别
Callable声明具有泛型和抛出异常,而Runnable没有,其次Callable有一个返回值 ,而Runnable没有
案例:

package Review;

import java.util.concurrent.Callable;

public class call {
public static void main(String[] args) {
    Callable<String> stringCallable = new Callable<String>() {
        @Override
        public String call() throws Exception {
            for (int i = 0; i < 20; i++) {
                System.out.println(Thread.currentThread().getName()+".........."+i);
            }
            return "callable";
        }
    };

    new Thread(new Runnable() {
        @Override
        public void run() {
            for (int i = 0; i < 20; i++) {
                System.out.println(Thread.currentThread().getName()+"..........."+i);
            }
        }
    }).start();

    try {
        stringCallable.call();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
}

Future接口:返回将要完成的结果
使用两个线程计算0-100的值,第一个线程计算0-50,第二个线程计算21-100;

package Review;
import java.util.concurrent.*;
public class callFuture {
public static void main(String[] args) {
    ExecutorService service = Executors.newFixedThreadPool(2);
    Future<Integer> future1 = service.submit(new Callable<Integer>() {
        @Override
        public Integer call() throws Exception {
            System.out.println("计算机0-50开始");
            int sum = 0;
            for (int i = 0; i < 50; i++) {
                sum+=i;
            }
            System.out.println("计算机0-50结束");
            return sum;
        }
    });

    Future<Integer> future2 = service.submit(new Callable<Integer>() {
        @Override
        public Integer call() throws Exception {
            System.out.println("计算机51-100结束");
            int  sum = 0;
            for (int i = 51; i <= 100; i++) {
                sum+=i;
            }
            System.out.println("计算机51-100结束");

            return sum;
        }
    });
    try {
        future1.get();
        future2.get();
        System.out.println(future1.get()+future2.get());
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
    service.shutdown();
}
}

线程状态
new状态:线程创建完成,通过start()进入Ready就绪状态,所有工作准备完毕,os系统选中,进入running运行状态,线程中run()执行结束,线程完成执行。在运行状态时,当有线程加入join()时,会停止该线程的执行,直接去执行加入线程的,当前线程进入无限制等待Waiting状态,只有加入线程执行结束,当前线程才会继续执行。通过sleep会使线程进入睡眠状态,限期等待TImed Waiting状态,睡眠时间到,线程继续执行。如果对线程进行了加锁操作,就是synchronized,线程就会进入阻塞状态,当获得锁之后,线程又会继续执行,最终Terminated终止状态,

1.加入线程join,会阻塞当前线程,等待加入线程运行结束,当前线程才会继续运行,
案例:

package Review;
public class addJoin {
public static void main(String[] args) {
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            for (int i = 0; i < 30; i++) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"......"+i);
            }
        }
    };
    Thread thread1 = new Thread(runnable, "tt");
    try {
        thread1.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    for (int i = 30; i < 69; i++) {
        System.out.println(Thread.currentThread().getName()+"......"+i);
    }
    thread1.start();
}
}

线程睡眠

package Review;
import java.util.concurrent.*;
public class sleep {
public static void main(String[] args) {
    ExecutorService service = Executors.newFixedThreadPool(1);
    Future<Integer> future  = service.submit(new Callable<Integer>() {
        @Override
        public Integer call() throws Exception {
            int sum = 0;
            for (int i = 0; i < 20; i++) {
                sum+=i;
                Thread.sleep(200);
            }
            return sum;
        }
    });
    try {
        System.out.println(future.get());
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
}
}

线程优先级
setPriorityL线程优先级,使用方法:线程点setpriority,线程优先级分别为1-10,默认为5.当优先级最高时,cpu会优先执行。
package Review;

package Review;

public class setPriority extends Thread{
@Override
public void run() {
    for (int i = 0; i < 20; i++) {
        System.out.println(Thread.currentThread().getName()+"..."+i);
    }
}

public static void main(String[] args) {
    setPriority priority = new setPriority();
    Thread thread1 = new Thread(priority, "1");
    Thread thread2 = new Thread(priority, "2");
    thread1.setPriority(5);
    thread2.setPriority(10);
    thread1.start();
    thread2.start();
}
}

守护线程
使用方法:线程名称.setDaemon(true) 将线程设置为守护线程,线程有两类:用户(前端线程),后台(守护线程)如果所有前端线程执行完毕,那么后台线程自动结束,守护线程是为前端线程保驾护航的。

线程放弃
当前线程主动放弃时间片,进入就绪状态,竞争下一次时间片。

package Review;
public class yield extends Thread{
@Override
public void run() {
    for (int i = 0; i < 20; i++) {
        System.out.println(Thread.currentThread().getName()+"..."+i);
        Thread.yield();
    }
}

public static void main(String[] args) {
    yield yield = new yield();

    Thread thread1 = new Thread(yield, "1");
    Thread thread2 = new Thread(yield, "2");
    thread1.start();
    thread2.start();
}
}

线程通信
等待方法:
public final void wait()
public final void wait(long timeout):
必须在对obj加锁的同步代码块中,在一个线程中调用obj.wait时,此线程会释放其拥有的标记,哦同时线程阻塞在等待队列中,释放锁,进入等地啊队列
通知方法:
public final notify()
public final viod notfiy()

synchronized
同步方法:synchronized 返回值 方法名称 参数列表(){ //当前对象进行加锁
//加锁代码}
只有拥有对象互斥标记的线程,才能够进入该加锁的对象,线程在执行完之后,就会释放锁标记,给下一个线程。
案例:模拟3个窗口同时卖一百张票
方法一:同步代码块

package Review;
public class ticket implements Runnable{
private static int tic = 100;
@Override
public void run() {
    while (true){
        synchronized (this){
            if (tic < 0){
                break;
            }
            System.out.println(Thread.currentThread().getName()+"卖了第"+tic+"票");
            tic--;
        }
    }
}

public static void main(String[] args) {
    ticket ticket = new ticket();
    new Thread(ticket,"1").start();
    new Thread(ticket,"2").start();
    new Thread(ticket,"3").start();
}
}

方法二:同步方法
案例:模拟3个窗口同时卖一百张票

package Review;
public class ticketSynchronized extends Thread{
private static int ticket = 100;
@Override
public void run() {
    while (true){
        if (!method()){
            break;
        }
    }
}
public synchronized static boolean method(){
    if (ticket <= 0){
        return false;
    }
    System.out.println(Thread.currentThread().getName()+"卖了第"+ticket+"票");
    ticket--;
    return true;
}

public static void main(String[] args) {
    ticketSynchronized ticket  = new ticketSynchronized();
    new Thread(ticket,"1").start();
    new Thread(ticket,"2").start();
    new Thread(ticket,"3").start();
}
}

方法三:锁 Lock

package Review;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Locks extends Thread{
private static int ticket = 100;
Lock lock = new ReentrantLock();

@Override
public void run() {
    lock.lock();
    while (true){
        if (ticket <= 0){
            break;
        }
        System.out.println(Thread.currentThread().getName()+"卖了第"+ticket+"票");
        ticket--;
    }
    lock.unlock();
}

public static void main(String[] args) {
    Locks locks = new Locks();
    new Thread(locks,"1").start();
    new Thread(locks,"2").start();
    new Thread(locks,"3").start();
}
}

Lock
lock锁:是和synchronized具有相同功能且比它结构灵活、实用性更大、功能更加完善、性能更优越的锁,
方法:
void lock():获得锁,执行若被线程占用,则等待
boolean tryLock:尝试获得锁,不会造成线程阻塞,成功返回true,失败返回false
void unlock():释放锁,

重入锁:ReentranLock
一个可以重入互斥Lock且具有和synchronized相同功能并可以扩展的锁,ReentrantLock:用Lock接口实现,与synchronized一样具有互斥功能
案例使用ReentrantLock对数组增加两个元素

package Review;
import java.util.Arrays;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Reentrant {
Lock lock = new ReentrantLock();
private String[] str = {“A”,“B”,"","",""};
private int index = 0;
public void add(String value){
lock.lock();
str[index] = value;
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
index++;
System.out.println(Thread.currentThread().getName());
lock.unlock();
}
public String[] get(){
return str;
}

public static void main(String[] args) {
    Reentrant reentrant = new Reentrant();
    Runnable runnableA = new Runnable() {
        @Override
        public void run() {
            System.out.println("a添加");
            reentrant.add("666");
        }
    };
    Runnable runnableB = new Runnable() {
        @Override
        public void run() {
            System.out.println("b添加");
            reentrant.add("777");
        }
    };
    Thread threadA = new Thread(runnableA, "A");
    Thread threadB = new Thread(runnableB, "B");
    threadA.start();
    threadB.start();
    try {
        threadA.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    try {
        threadB.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println(Arrays.toString(reentrant.get()));
}
}

读写锁ReentrantReadWriteLock
读写锁支持一写多读,读写分离,可以分别分配读写锁,可以支持多次分配读写锁,使得多个线程并发执行,
读锁不会互斥,写锁会,写不能读,都不能写,两个线程都在读不会互斥,
规则:写写互斥,阻塞;读写互斥,读阻塞写,写阻塞读,读读不会互斥

案例:synchronized和ReenTrantReadWriteLock读写时间对比,创建20个线程,18个读线程,2个写线程,进行比较
读写锁案例:
package Review;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class TestRW {
ReentrantReadWriteLock locks = new ReentrantReadWriteLock();
ReentrantReadWriteLock.ReadLock read = locks.readLock();
ReentrantReadWriteLock.WriteLock write = locks.writeLock();
String value;
public String getValue(){
read.lock();
try {
Thread.sleep(1000);
System.out.println(“写入”+value);
return this.value;
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
read.unlock();
}
return this.value;
}
public String setValue(String value){
write.lock();
try {
Thread.sleep(1000);
System.out.println(“写入”+value);
return this.value;
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
write.unlock();
}
return this.value;
}
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(20);
TestRW rw = new TestRW();
Runnable r = new Runnable() {
@Override
public void run() {
rw.getValue();
}
};
Runnable w = new Runnable() {
@Override
public void run() {
rw.setValue(“ee”+new Random().nextInt(100));
}
};

    long start = System.currentTimeMillis();
    for (int i = 0; i < 2; i++) {
        service.submit(w);
    }
    for (int i = 0; i < 18; i++) {
        service.submit(r);
    }
    long end = System.currentTimeMillis();
    service.shutdown();

    while (!service.isTerminated()){ //线程空转,保证所有线程执行完成

    }
    System.out.println("消耗时间:"+(end-start));
}

}

互斥锁案例:

package Review;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantLock;
public class reentrantRW {
ReentrantLock lock = new ReentrantLock(); //互斥锁

String value;
public String getValue(){
    lock.lock();
    try {
        Thread.sleep(1000);
        System.out.println("读入"+value);
        return  this.value;
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        lock.unlock();
    }
    return value;
}

public String setValue(String value){
    lock.lock();
    try {
        System.out.println("写入"+value);
        return this.value;
    } finally {
        lock.unlock();
    }
}
public static void main(String[] args) {
    reentrantRW rw = new reentrantRW();
    ExecutorService service = Executors.newFixedThreadPool(20);
    Runnable write = new Runnable() {
        @Override
        public void run() {
            rw.setValue("ee:"+ new Random().nextInt(100));
        }
    };

    Runnable read = new Runnable() {
        @Override
        public void run() {
            rw.getValue();
        }
    };

    long start = System.currentTimeMillis();
    for (int i = 0; i < 2; i++) {
        service.submit(write);
    }

    for (int i = 0; i < 18; i++) {
        service.submit(read);
    }

    service.shutdown();

    while (!service.isTerminated()){  //线程空转,保证所有线程都执行完毕

    }
    long end = System.currentTimeMillis();
    System.out.println(end-start);
}

}

为了方便 全部写在一起,建议分开写。两个案例最后都是输出了读取和输入,但是读写锁只需要3秒左右,而互斥锁则需要18秒左右,而互斥锁还可能存在阻塞清空;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值