程序的一条执行路径
public class ThreadDemo {
public static void main(String[] args) {
new T1().start();
for (int i = 0; i<10; i++){
try {
TimeUnit.MICROSECONDS.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("main");
}
}
private static class T1 extends Thread{
@Override
public void run(){
for (int i = 0; i<10; i++){
try {
TimeUnit.MICROSECONDS.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("T1");
}
}
}
}
public class NewThread {
//继承thread
static class MyThread extends Thread{
@Override
public void run(){
System.out.println("HELLO MyThrwad");
}
}
//实现Runnabe
static class MyRun implements Runnable{
@Override
public void run() {
System.out.println("HELLO MyRun");
}
}
//@Function
public static void main(String[] args) {
new MyThread().start();
new Thread(new MyRun()).start();
new Thread(()->{
System.out.println("Hello Lambda");
}).start();
}
//启动线程的方式 1:Thread 2.Runable 3.Executors.newCachedThrad(线程池)实际上也是1、2的一种
状态新建一个线程是 NEW状态(没屌用start),调用start之后之后线程 会被线程调度器来执行整体的状态是Runable状态(内部有ready和Runing俩状态),其中ready是就绪状态, 继续状态就是将线程放到cpu的等待队列当中,真正的放到cpu中运行的是Runing状态,处于Runing状态的线程可以通过yield方法重新回到Ready,直到线程被调度器选中执行重新到Runing状态,执行结束后Teminated状态,到达Teminated不能再次start,也不能回到runable状态
阻塞状态:Blocked 进入synchronized代码块没有获得没有获得锁之前是阻塞状态
等待:waiting 在runable状态是调用了o.wait(time)、t.join(time)、LockSupport.park()进入waiting状态,再调用o.nitify()、o.nitifyAll()、LockSupport.unpark(),又回到Runable状态
时间等待:Timewaiting(时间结束后会自动回去) 在runable状态是调用了Thread.sleep(time)
o.wait(time)、t.join(time)、LockSupport.parkNanos()、LockSupport.parkUntill()时间结束之后自动回到Runable状态
stop()废除不使用
interrupt 底层会使用没有使用它控制业务逻辑的
1.在同一个classloader中的classLoader都是单例模式。
2.一个object只能锁住一个对象
1.起一个线程 加载图片下载文件
import java.util.concurrent.TimeUnit;
/**
* @Author:
* @Date: 2022/08/08/22:09
* @Description:
**/
//singletonMode 单例模式
public class Account {
String name;
double balance;
public synchronized void set(String name,double balance){
this.name = name;
/* try{
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
this.balance = balance;
}
public /*synchronized*/ double getBalance(String name){
return this.balance;
}
public static void main(String[] args) {
Account account = new Account();
new Thread(() -> account.set("zkj", 100.0)).start();
try{
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(account.getBalance("zkj"));
try{
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(account.getBalance("zkj"));
}
}
new Account的时候就设置了balance这样1s后能读到正确的值100.0,再过2s后能读到正确的值100.0
import java.util.concurrent.TimeUnit;
/**
* @Author:
* @Date: 2022/08/08/22:09
* @Description:
**/
//singletonMode 单例模式
public class Account {
String name;
double balance;
public synchronized void set(String name,double balance){
this.name = name;
try{
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.balance = balance;
}
public /*synchronized*/ double getBalance(String name){
return this.balance;
}
public static void main(String[] args) {
Account account = new Account();
new Thread(() -> account.set("zkj", 100.0)).start();
try{
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(account.getBalance("zkj"));
try{
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(account.getBalance("zkj"));
}
}
new Account的时候就没有设置balance,而是等待1s后进行设置balance,这样1s后能不读到正确的值100.0,而是默认值0,再过2s后能读到正确的值100.0
import java.util.concurrent.TimeUnit;
/**
* @Date: 2022/08/08/22:09
* @Description:
**/
//singletonMode 单例模式
public class Account {
String name;
double balance;
public synchronized void set(String name,double balance){
this.name = name;
try{
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.balance = balance;
}
public synchronized double getBalance(String name){
return this.balance;
}
public static void main(String[] args) {
Account account = new Account();
new Thread(() -> account.set("zkj", 100.0)).start();
try{
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(account.getBalance("zkj"));
try{
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(account.getBalance("zkj"));
}
}
new Account的时候就没有设置balance,而是等待1s后进行设置balance,但是由于getBalance操作设置的了锁,这样无法读取数据,只能等待设置了值之后,再进行读操作,这样1s后能读到正确的值100.0,而是默认值0,再过2s后能读到正确的值100.0
一个同步方法可以调用另外一个同步方法,一个线程已经拥有某个对象的锁,再次申请的时候仍会得到该对象的锁,也就是说synchronized获得的是可重入的锁
import java.util.concurrent.TimeUnit;
/**
* @Date: 2022/08/09/00:18
* @Description: 一个同步方法可以调用另外一个同步方法,一个线程已经拥有某个对象的锁,再次申请的时候
* 仍会得到该对象的锁,也就是说synchronized获得的是可重入的锁
**/
public class reentrant {
synchronized void m1(){
System.out.println("m1 start");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
m2();
System.out.println("m1 end");
}
synchronized void m2() {
System.out.println("m1 start");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("m1 end");
}
public static void main(String[] args) {
new reentrant().m1();
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4uc1vByy-1660233819593)(…/Library/Application Support/typora-user-images/image-20220809214249757.png)]
M1()方法由某线程创建,m2()也需要枷锁是同一个线程的同一个锁,m2()也会得到这把锁
如果synchronize不是可重入的锁子类调用父类的方法会死锁
import java.util.concurrent.TimeUnit;
/**
* @Date: 2022/08/10/21:29
* @Description:
**/
public class synceexception {
/**
* 程序在执行过程中,如果出现异常,默认情况锁会被释放
* 所以,在并发处理的过程,有异常要多加小心,不然可能会发生不一致的情况,
* 比如,在一个web app处理过程中,多个servlet线程共同访问同一个资源,这时如果异常处理不合适
* 在第一个线程中抛出异常,其他线程就会进入同步代码区,有可能会访问到异常产生时的数据
* 因此要非常小心的处理同步业务逻辑中的异常
*/
int count = 0;
synchronized void m() {
System.out.println(Thread.currentThread().getName() + "start");
while (true) {
count ++;
System.out.println(Thread.currentThread().getName() + "count =" + count);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (count == 5){
int i = 1/0; //此处抛出异常,锁将被释放,要不想被释放,可以在此处加一个catch,之后让循环继续
System.out.println(i);
}
}
}
public static void main(String[] args) {
synceexception synceexception = new synceexception();
Runnable runnable = new Runnable() {
@Override
public void run() {
synceexception.m();
}
};
new Thread(runnable,"t1").start();
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(runnable,"t2").start();
}
}
可见t1抛出异常的同时释放了锁,t2获得了锁
jdk早期的是重量级锁是向操作系统申请的(OS),后来随着java开始有越来越多的高并发的项目,Synchronized的效率就太低了,经过改造才有了现在的锁
现在的锁是有锁升级的概念
偏向锁:sync(Object)如果只有一个线程 只markwoed 记录这个线程ID
自选锁 :此时如果出现了线程争用这个锁 争用的线程就会自旋起来(默认的次数是10)此时锁升级为自旋锁
重量级锁:10次之后会升级为重量级锁,向OS操作系统申请资源,此时的锁不在占用cpu,变为等待状态,但是锁只能升级不能降级
Atomicl 、lock都是自旋锁,占用cpu但是不访问操作系统,是在用户态处理效率要高于内核态
执行时间长的使用重量级锁,