> 文章列表 > java记录-多线程与锁

java记录-多线程与锁

java记录-多线程与锁

JAVA的多线程

Thread线程类,实现了Runable接口
JAVA是抢占式调度,就是优先级高的先获取CPU资源,但并不意味它每一时刻都最快

创建新的线程的方法

1、创建Thread子类并重写run方法

public class MyThread extends Thread{@Overridepublic 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{@Overridepublic 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();//自定义的锁@Overridepublic 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)用