------Java培训、Android培训、iOS培训、.Net培训、期待与您交流------
1.Lock锁的概述
多线程问题之Lock锁
Lock锁包含lock()跟unlock()方法与synchronized()作比较
synchronized 一但用过该锁对象,就会自动释放锁然后让多线程抢占该锁对象,而lock需要加锁与释放锁配合使用
注意如果不释放锁对象,则一单获得锁就一直是同一个线程对象在运行程序
Lock锁包含lock()跟unlock()方法与synchronized()作比较
synchronized 一但用过该锁对象,就会自动释放锁然后让多线程抢占该锁对象,而lock需要加锁与释放锁配合使用
注意如果不释放锁对象,则一单获得锁就一直是同一个线程对象在运行程序
//以电影院售票为例:
//SellTickets售票方法继承自Thread
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SellTickets extends Thread {
public static int tickets = 100 ;
// 创建锁对象
public static Lock lock = new ReentrantLock() ;
@Override
public void run() {
while(true){
// 加锁
lock.lock() ;
if(tickets > 0) {
try {
Thread.sleep(100) ;
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName() + "出售第" + (tickets--) + "张票");
}
// 释放锁
lock.unlock() ;
}
}
}
//测试类
public class ThreadTest {
public static void main(String[] args) {
// 创建线程对象
SellTickets t1 = new SellTickets() ;
SellTickets t2 = new SellTickets() ;
SellTickets t3 = new SellTickets() ;
// 给线程设置名称
t1.setName("窗口1") ;
t2.setName("窗口2") ;
t3.setName("窗口3") ;
// 启动线程
t1.start() ;
t2.start() ;
t3.start() ;
}
}
2. 死锁: 是多个线程在抢占CPU的资源的时候,出现了相互等待的状态就叫死锁
//Mythread类
public class MyThread extends Thread {
private Object objA = new Object();
private Object objB = new Object();
private boolean flag ;
public MyThread(boolean flag){
this.flag = flag ;
}
@Override
public void run() {
if(flag){
synchronized(objA){
System.out.println("true....objA......");
synchronized(objB){
System.out.println("true....objB.....");
}
}
}else {
synchronized(objB){
System.out.println("false....objB......");
synchronized(objA){
System.out.println("false....objA.....");
}
}
}
}
}
//测试类为:
public class ThreadTest2{
public static void main(String[] args) {
// 创建线程对象
MyThread t1 = new MyThread(true) ;
MyThread t2 = new MyThread(false) ;
// 启动线程
t1.start() ;
t2.start() ;
}
}
3. 线程池
线程池的使用步骤:
a: 获取一个线程池
Executors这个类下的方法:
public static ExecutorService newCachedThreadPool(): 根据任务的数量来创建线程对应的线程个数
public static ExecutorService newFixedThreadPool(int nThreads): 固定初始化几个线程
public static ExecutorService newSingleThreadExecutor(): 初始化一个线程的线程池
b: 向线程池中提交任务
Future
submit(Runnable task)
Future
submit(Callable
task)
停止线程池:
void shutdown()
4. 实现多线程的第3种方式
//a:创建MyCallable类并实现Callable接口
import java.util.concurrent.Callable;
public class MyCallable implements Callable {
@Override
public Object call() throws Exception {
for(int x = 0 ; x < 100 ; x++){
System.out.println(Thread.currentThread().getName() + "----" + x);
}
return null;
}
}
//b:创建测试类:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CallableTest {
public static void main(String[] args) {
// 创建对象
MyCallable callable = new MyCallable() ;
// 获取一个线程池
ExecutorService executorService = Executors.newFixedThreadPool(2) ;
// 提交任务
executorService.submit(callable) ;
// 关闭线程池
executorService.shutdown() ;
}
}
// 我们如何使用匿名内部类的方式实现多线程?
public class MyThreadTest{
public static void main(String[] args) {
//两种方式: 使用Thread类
new Thread() {
@Override
public void run() {
for(int x = 0 ; x < 100 ; x++){
System.out.println(getName() + "---" + x);
}
}
}.start();
// 通过实现Runnable接口实现多线程
new Thread(new Runnable() {
@Override
public void run() {
for(int x = 0 ; x < 100 ; x++){
System.out.println(Thread.currentThread().getName() + "---" + x);
}
}
}).start() ;
}
}
5. 多线程有几种实现方案,分别是哪几种?
答: 有两种 , 第一种定义一个类然后让这个类继承Thread类 , 第二种定义一个类然后让这个类实现Runnable接口
同步有几种方式,分别是什么?
答: 有2中,第一种是使用同步代码块, 第二种使用同步方法
启动一个线程是run()还是start()?它们的区别?
答: 启动一个线程使用的是start方法
run方法中封装的都是要被线程执行的代码,而start方法是启动线程
sleep()和wait()方法的区别
答: sleep方法是使线程进入休眠状态,可以指定休眠的时间
wait()是线程处于等待状态
sleep方法不释放同步锁
wait方法是释放同步锁
答: 有两种 , 第一种定义一个类然后让这个类继承Thread类 , 第二种定义一个类然后让这个类实现Runnable接口
同步有几种方式,分别是什么?
答: 有2中,第一种是使用同步代码块, 第二种使用同步方法
启动一个线程是run()还是start()?它们的区别?
答: 启动一个线程使用的是start方法
run方法中封装的都是要被线程执行的代码,而start方法是启动线程
sleep()和wait()方法的区别
答: sleep方法是使线程进入休眠状态,可以指定休眠的时间
wait()是线程处于等待状态
sleep方法不释放同步锁
wait方法是释放同步锁
6.重点:单例设计模式:
思想: 保证这个类的对象在内存中只有一份
思想: 保证这个类的对象在内存中只有一份
有两种:饿汉式跟懒汉式
(1) 单例设计模式之饿汉式:上来用静态先随着类的加载而加载创建一个对象
//单例设计模式之饿汉式:上来用静态先随着类的加载而加载创建一个对象
public class Student {
// 构造方法私有化
private Student() {}
// 创建类的对象
public static Student s = new Student() ;
// 提供一个静态的方法
public static Student getInstance() {
return s ;
}
}
//测试类为:
public class StudentTest {
public static void main(String[] args) {
// 获取Student对象
Student s1 = Student.getInstance() ;
Student s2 = Student.getInstance() ;
System.out.println(s1 == s2);
}
}
(2) 单例设计模式之懒汉式
//单例设计模式之懒汉式
public class Student {
//私有化构造方法
private Student() {}
// 提供一个静态变量
public static Student s = null ;
// 提供静态的方法
public static synchronized Student getInstance() {
if(s == null){
s = new Student() ;
}
return s ;
}
}
//测试类
public class StudentTest2 {
public static void main(String[] args) {
Student s1 = Student.getInstance() ;
Student s2 = Student.getInstance() ;
System.out.println(s1 == s2);
}
}