线程的基本概念
进程
假设硬盘上有一个简单的程序,这个程序叫QQ.exe,这个程序是一个静态的概念,当你双击它,弹出一个界面登陆进去,这时候叫做一个进程。进程相对于一个程序来说它是一个动态的概念。
线程
作为一个进程里面最小的执行单元他叫一个线程,用简单的话讲一个程序里不同的执行路径就叫做一个线程。
创建多线程方法1、继承Thread类,重写run()方法,调用start开启线程
package com.sun.test;
public class TestThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 200; i++) {
System.out.println("world");
}
}
public static void main(String[] args) {
TestThread testThread = new TestThread();
testThread.start();
for (int i = 0; i < 200; i++) {
System.out.println("hello");
}
}
}
创建多线程方法2、实现runnable,重写run方法
package com.sun.test;
public class TestThread1 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 200; i++) {
System.out.println("world");
}
}
public static void main(String[] args) {
TestThread1 testThread1 = new TestThread1();
new Thread(testThread1).start();
for (int i = 0; i < 200; i++) {
System.out.println("hello");
}
}
}
创建多线程方法3、从线程池启动
启动线程
-
new Thread().start();
-
new Threas(Runnable).start;
-
从线程池启动
线程里面的方法
sleep:当前线程暂停一段时间让给别的线程去执行。
Yield:当前线程正在执行的时候停下来进入等待队列。
join:自己在当前线程加入你调用Join的线程,本线程等待。等调用的线程运行完了,自己再去执行。
常见的线程状态
-
新建状态
-
Ready就绪状态
-
Running运行状态
-
Teminated结束状态
-
Waiting等待状态
-
Blocked阻塞状态
synchronized
-
public class T {
private int count = 10;
private object o = new object();
public void m() {
synchronized(o){ //任何线程要想执行下面的代码,必须先拿到o的锁
count--;
System.out.println(Thread.currentThread().getName()+"count="+count);
}
}
}
如果每次都定义一个锁的对象Object o 把它new出来那加锁的时候太麻烦每次都要new一个新的对象出来,所以有一个简单的方式就是synchronize(this)锁定当前对象就行。
public class T {
private int count = 10
public void m() {
synchronized(this){ //任何线程要想执行下面的代码,必须先拿到this的锁
count--;
System.out.println(Thread.currentThread().getName()+"count="+count);
}
}
}
public class T {
private int count = 10;
public synchronized void m() { //等同于synchronize(this)
count--;
System.out.println(Thread.currentThread().getName()+"count="+count);
}
}
synchronized保证了原子性,有保证了可见性
synchronized锁的是对象而不是代码,锁方法锁锁的是this,锁static方法锁的是class,锁方法和非锁方法是可以同时执行的,锁升级从偏向锁到自旋锁到重量级锁。
synchronized:系统自带、系统自动加锁、自动解锁、不可以出现多个不同的等待队列、默认进行四种锁状态升级
执行时间短,线程数少,用自旋
执行时间多,线程数多,用系统锁
偏向锁:记录这个线程ID
自旋锁:如果线程争用,就升级为自旋锁(线程数量少)
重量级锁:10次(线程数量多)
锁升级的过程
当我们使用synchronized的时候HotSpot实现:上来之后第一个去访问某把锁的线程,比如sync(Object),来了之后先在这个Object的头上面markdown记录这个线程(如果只有第一个线程访问的时候实际上是没有给这个Object加锁的,在内部实现的时候,只是记录线程的ID(偏向锁))。
偏向锁如果有线程争用的话,就升级为自旋锁。
自旋锁转圈10次后,升级为重量级锁,重量级锁就是去操作系统那里去申请资源