JAVA的多线程
Thread线程类,实现了Runable接口
JAVA是抢占式调度,就是优先级高的先获取CPU资源,但并不意味它每一时刻都最快
创建新的线程的方法:
1、创建Thread子类并重写run方法
public class MyThread extends Thread{
@Override
public void run(){
for(int i=0; i<100; ++i){
System.out.println(String.valueOf(i))
}
}//run方法封装线程的动作,直接调用它并不会启动线程,相当于普通方法调用
MyThread(){
super();
}
MyThread(String name){
super(name);
}
}
MyThread my1 = new MyThread();
MyThread my2 = new MyThread();
MyThread my3 = new MyThread("线程3");
my1.setName("线程1");
my2.setName("线程2");
System.out.println(my1.getName()); //如果未指定名称,默认为 Thread-0、Thread-1
System.out.println(my2.getName());
System.out.println(my3.getName());
//start方法才是启动线程的方法
my1.start();
my2.start();
my3.start();
获取目前正在执行的线程对象的引用(每次都不是同一个线程,因为不知道现在是哪个线程获得CPU资源在执行)
Thread th = Thread.currentThread();
获取与设置线程优先级(默认为5,越大优先级越高0~10)
my1.getPriority();
my1.setPriority(10);
使当前在运行的线程暂停执行
Thread.sleep(1000);
阻塞其他操作,等待线程死亡再继续
my1.join();
设置为守护线程(全为守护线程JVM直接终止,因为没有主线程了)
my1.setDaemon(true);
2、实现Runnable接口,重写run方法,在创建Thread时将对象作为参数传入并启动
这种方式可以让工作的类继承它自己的父类,而不是只继承一个Thread
其实Thread也是Runnable的实现类
public class MyWork implements Runnable{
@Override
public void run(){
for(int i=0; i<100; ++i)
System.out.println(Thread.currentThread().getName()+String.valueOf(i));
}
}
Thread th1 = new Thread(new MyWork());
Thread th2 = new Thread(new MyWork(), "线程2");
th1.setName("线程1");
th1.start();
th2.start();
同步锁
不懂这是啥的先学操作系统原理的同步异步章节
用同步代码块实现锁,里面是操作共享数据的语句
同步锁会降低单个线程的运行效率,但是保证了数据安全
synchronized(任意对象),这个任意对象是被当成一个锁用,但是必须保证所有线程能接触到的作为锁的对象是同一个!
下面是三个售票窗口并发买票的例子,如果不锁,会出现三个窗口同时卖同一张票的情况,这个叫幻象读
public class Main {
static long count = 0;
public static void main(String[] args){
Thread seller1 = new Thread(new ticketSeller(), "一号售票窗口");
Thread seller2 = new Thread(new ticketSeller(), "二号售票窗口");
Thread seller3 = new Thread(new ticketSeller(), "三号售票窗口");
seller1.start();
seller2.start();
seller3.start();
}
}
class ticketSeller implements Runnable{
static private int ticketNum = 100;//100张票
static Object lock = new Object();//自定义的锁
@Override
public void run() {
while(true){
synchronized (lock) {//使用同步代码块锁住操作共享对象的代码
if (ticketNum > 0) {
try {
Thread.sleep((new Random()).nextInt(1000));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName() + "卖出1张票,余票" + String.valueOf(--ticketNum) + "张");
} else {
System.out.println("票卖完了,请回吧");
break;
}
}
}
}
}
也可以直接对方法加锁,用这个方法都是加锁的。
同步方法的锁是this对象,只使用一个对象的同步方法就是唯一的
synchronized void sellTicket(){
if (ticketNum > 0) {
try {
Thread.sleep((new Random()).nextInt(1000));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName() + "卖出1张票,余票" + String.valueOf(--ticketNum) + "张");
} else {
System.out.println("票卖完了,请回吧");
break;
}
}
也可以对静态方法加锁
同步静态方法的锁是字节码文件对象(ticketSeller.class),唯一
static synchronized void sellTicket(){
if (ticketNum > 0) {
try {
Thread.sleep((new Random()).nextInt(1000));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName() + "卖出1张票,余票" + String.valueOf(--ticketNum) + "张");
} else {
System.out.println("票卖完了,请回吧");
break;
}
}
线程安全类
StringBuffer、vector(类似ArrayList)、Hashtable(类似HashMap)
此外,Collections类给出了方法返回线程安全的类实现
Collections.synchronizedList(List<T>);
Collections.synchronizedSet(Set<T>);
Collections.synchronizedMap(Map<T>);
等等
Lock锁
更加清晰,你能知道锁的位置和何时释放
其实现类为ReentrantLock
Lock lock = new ReetrantLock();
lock.lock();//阻塞其他进程
lock.unlock();//释放资源
生产者消费者模式
Object类有三个方法,wait()、notify()和notifyAll()用于实现
wait()直接阻塞,等待唤醒
notifyAll()是唤醒其他在等的线程
配合synchronized(A)用