- 多线程
多线程是一种在实际编程当中很实用的编程手段和思路,但是多线程并不是只有优点,在使用多线程多过程当中,也会出现非常多的问题,这里我们做一个概括:
优点:
在大多数情况下,使用多线程可以充分的利用多核cpu的资源,极大的提升程序运行的效率。
缺点:
当某一个资源被多个线程共享时,这个资源可能会出现线程安全的问题。
当线程过多时,可能会因为程序编写不当等各种原因导致出现死锁,cpu负载过高的情况。
1.1线程安全
除去程序员编写不当的问题我们无法控制之外,解决线程安全问题就成了多线程程序编写最大的问题。
我们一句话概括什么是线程安全:
当多个线程同时 对同一个共享资源进行非原子操作(如 :修改某个共享资源的数据时),将会出现线程安全问题。
class Counter {
private int count;
public void increase() {
++this.count;
}
public int getCount() {
return this.count;
}}public class Main11 {
private static final int CNT = 50000;
private static final Counter counter = new Counter();
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(() -> {
for (int i = 0; i < CNT; i++) {
counter.increase();
}
});
Thread thread2 = new Thread(() -> {
for (int j = 0; j < CNT; j++) {
counter.increase();
}
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(counter.getCount());
}}
以上是一个最简单的自增例子,我们预期的结果是两个线程各自增50000次,最后输出100000,但是结果总在变化且并不会出现我们预期的结果。
1.2类锁与对象锁
类锁和对象锁是Java中用于实现多线程同步的两种机制。
- 对象锁(Object Lock)
- 对象锁是基于对象实例的,每个对象都有一个与之关联的锁。当一个线程访问一个对象的
synchronized
方法或synchronized
代码块时,它就获取了这个对象的锁。这意味着,如果一个对象有多个synchronized
方法,同一时刻只有一个线程可以执行其中一个方法,因为这些方法共享同一个对象锁。对象锁的范围是对象实例级别的,不同对象实例的锁是互相独立的。一个线程获取了某个对象的锁并不影响其他对象实例的锁。
- 对象锁是基于对象实例的,每个对象都有一个与之关联的锁。当一个线程访问一个对象的
- 类锁(Class Lock)
- 类锁是基于类的,它是在类级别上实现的锁。当一个线程访问一个类的
static synchronized
方法或synchronized
代码块时,它获取了该类的锁,而不是某个对象的锁。类锁的范围是整个类,无论有多少个类的实例,同一时刻只能有一个线程执行该类的synchronized
方法或代码块。类锁在并发控制上更加广泛,适用于一些类级别的操作。
- 类锁是基于类的,它是在类级别上实现的锁。当一个线程访问一个类的
2.sync
2.1sync的锁类型:
对象锁:方法锁
方法锁是用synchronized修饰的一个类方法,作用方法即是方法作用域,除了这个方法要同步,其余不需要
public class SynchronizedObjectMethod implements Runnable{
private static SynchronizedObjectMethod instance=new SynchronizedObjectMethod();
public synchronized void method(){
System.out.println("我是对象锁的方法修饰符形式。我叫"+Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"运行结束");
}
@Override
public void run() {
method();
}
public static void main(String[] args) {
Thread thread1 = new Thread(instance);
Thread thread2 = new Thread(instance);
thread1.start();
thread2.start();
while(thread1.isAlive()||thread2.isAlive()){
}
System.out.println("finish");
}
}
对象锁:代码块形式
代码块锁就是常用的同步方法块,synchronized锁住的是它里面的对象,作用域就是synchonized{}里面的代码
public class SynchronizedObjectCodeBlock implements Runnable{
private static SynchronizedObjectCodeBlock instance=new SynchronizedObjectCodeBlock();
Object lock1=new Object();
@Override
public void run() {
synchronized (lock1){
System.out.println("我是对象锁的代码块形式。我叫"+Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"运行结束");
}
}
public static void main(String[] args){
Thread thread1 = new Thread(instance);
Thread thread2 = new Thread(instance);
thread1.start();
thread2.start();
while(thread1.isAlive()||thread2.isAlive()){
}
System.out.println("finish");
}
}
类锁:class形式
class形式说的是synchronized()括号里使用的锁是class对象,所谓class对象指得是java文件对应的一个java.lang.class对象,所有该类生成的对象共有这个class对象 类加载机制,所以这个锁锁住了这个类生成的所有对象
public class SynchronizedClassClass implements Runnable{
private static SynchronizedClassClass instance1=new SynchronizedClassClass();
private static SynchronizedClassClass instance2=new SynchronizedClassClass();
public void method(){
synchronized (SynchronizedClassClass.class){
System.out.println("我是类锁的形式之一:修饰.class。我叫"+Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"运行结束");
}
}
@Override
public void run() {
method();
}
public static void main(String[] args) {
Thread thread1 = new Thread(instance1);
Thread thread2 = new Thread(instance2);
thread1.start();
thread2.start();
while(thread1.isAlive()||thread2.isAlive()){
}
System.out.println("finish");
}
}
在这个案例中,存在两个SynchronizedClassClass对象,但是不能同时访问同步代码
类锁:static形式
static形式说的是static修饰synchronized修饰的方法,即static synchronized methodName,作用方法还是这个类的class对象
public class SynchronizedClassStatic implements Runnable{
private static SynchronizedClassStatic instance1=new SynchronizedClassStatic();
private static SynchronizedClassStatic instance2=new SynchronizedClassStatic();
public static synchronized void method(){
System.out.println("我是类锁的形式之一:加static修饰。我叫"+Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"运行结束");
}
public void method2(){
System.out.println("我是非静态方法,我叫"+Thread.currentThread().getName());
}
@Override
public void run() {
method();
method2();
}
public static void main(String[] args) {
Thread thread1 = new Thread(instance1);
Thread thread2 = new Thread(instance2);
thread1.start();
thread2.start();
while(thread1.isAlive()||thread2.isAlive()){
}
System.out.println("finish");
}
}