进程和线程
1. 进程:一个正在执行中的程序就是一个进程,系统会为这个进程发配独立的资源。
2. 线程:具体执行任务的最小单位,一个进程至少包含一个线程。
进程与线程的联系:
1.一个进程至少包含一个线程“主线程(main)”,运行起来就执行的线程
2.线程间的资源是共享的,是统一由进程申请的
3.线程间可以通信
io 为阻塞io
nio 为非阻塞io =》netty框架
进程内多个线程间的切换(统一由内核进行调度)
多线程实现:
1.继承Thread类
public class BThread extends Thread{
@Override
public void run() {
for (int i=0;i<10;i++){
System.out.println("我是run");
}
}
public static void main(String[] args) {
for (int i=0;i<10;i++){
System.out.println("main");
}
new BThread().start();
for (int i=0;i<10;i++){
System.out.println("main2");
}
}
}
2.实现Runnable接口
public class BRunnable implements Runnable{
@Override
public void run() {
for (int i=0;i<10;i++){
System.out.println("我是run");
}
}
public static void main(String[] args) {
for (int i=0;i<10;i++){
System.out.println("main");
}
new Thread(() -> System.out.println("lamda")).start();
for (int i=0;i<10;i++){
System.out.println("main2");
}
}
}
-------------------------------------------------------
//lamda表达式实现
public class BRunnable {
public static void main(String[] args) {
for (int i=0;i<10;i++){
System.out.println("main");
}
new Thread(() -> System.out.println("lamda")).start();
for (int i=0;i<10;i++){
System.out.println("main2");
}
}
}
实现含返回值的线程(继承Callable接口)
获取返回值 .get()方法 该方法是阻塞属性的
public class BCallable /*implements Callable<Integer>*/{
/*@Override
public Integer call() throws Exception {
Thread.sleep(2000);
return 1;
}*/
public static void main(String[] args) throws Exception {
System.out.println("2");
FutureTask<Integer> future = new FutureTask<>(() -> {
Thread.sleep(2000);
return 1;
});
System.out.println("3");
new Thread(future).start();
Integer integer = future.get();
System.out.println("4");
System.out.println(integer);
System.out.println("5");
}
}
守护线程(对于后台支持非常有用 如:垃圾回收 JVM等)
线程分为 用户线程 和 守护线程
······用户线程优先级高于守护线程 (守护线程为用户线程提供服务)
···········例:JVM在终止任务前等待所有用户线程完成其任务
设置:setDaemon(true) 该线程被设置为守护线程
CPU内存模型:(多级缓存机制)
- cpu通过数据一致性协议来保证各程序读取数据的一致。
- 伪共享:数据一致性导致数据在一处一经更改,则该数据在其他缓存中失效
- 指令重排
磁盘中数据按顺序读取
主存中数据按随机读取
- cup经过一二三级缓存依次进行查询查到则返回,未查到则在内存中进行读取
JMM(JAVA内存模型)
JAVA中的锁:
synchronized jdk内置锁
java反编译可见:指令代码 锁由两个标志 monitorenter(获取锁) monitorexit(释放锁)
反编译指令:D:\workingspace\java\IDEA\prac\out\production\prac\com\idea\thread>javap -v BThread.class
synchronzied锁升级:
Lock接口 显式锁
所要实现的方法
@Override
public void lock() {}
@Override
public void lockInterruptibly() throws InterruptedException {}
@Override
public boolean tryLock() { return false;}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {return false;}
@Override
public void unlock() {}
@Override
public Condition newCondition() {return null;}
//1.
try{
lock.lock();
}catch(){
}finally{
lock.unlock();
}
//2.
if(lock.tryLock()){
try{
lock.lock();
}catch(){
}finally{
lock.unlock();
}
}else{
}
ReentrantLock
ReadWriteLock接口
读锁 写锁(独占锁 共享锁)
公平锁 非公平锁
乐观锁 被关锁
可重入锁 不可重入锁
volatile
java虚拟机提供的轻量级的同步机制
- 保证了数据的可见性,线程访问变量会跳过自己的缓存区从主存中进行读写
- 禁止指令重排
- 不保证原子性
线程的生命周期
HashMap线程不安全 (ConcurrentHashMap 线程安全且效率高于HashTable)
HashTable线程安全
终止线程的运行
- 1.设立标志位终止
public class BThread extends Thread {
public volatile boolean flag = true;
String name = "";
public BThread(String name) {
this.name = name;
}
@Override
public void run() {
while (flag) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.name + ":" + Constant.a--);
}
}
public static void main(String[] args) throws InterruptedException {
BThread a = new BThread("zssmb");
a.start();
Thread.sleep(1000);
a.flag = false;
}
}
- 2.抛出InterruptedException 异常进行线程终止(打断线程)
必须包含阻塞方法
public class BThread extends Thread {
public volatile boolean flag = true;
String name = "";
public BThread(String name) {
this.name = name;
}
@Override
public void run() {
try {
while (flag) {
Thread.sleep(100);
System.out.println(this.name + ":" + Constant.a--);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
BThread a = new BThread("zssmb");
a.start();
Thread.sleep(1000);
a.interrupt();
}
}
死锁
两个线程A和B,A拿到线程B的锁的同时,B也拿到了线程A的锁,导致两个线程均无法获得各自的锁而形成的死锁
多线程的三大特性
1.原子性()
2.有序性(指令重排问题)
3.可见性(主存和工作内存数据的一致性volatile)
线程池
线程任务传递给线程池,线程池自行调度
提交方法:submit(Runnable task) 提交一个可运行的任务执行,并返回一个表示该任务的未来。
自定义线程池:
public class MyThreadPool {
public static void main(String[] args) throws InterruptedException {
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
4,
8,
10,
TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(300),
new ThreadFactory() {
private final AtomicInteger poolNumber = new AtomicInteger(1);
private ThreadGroup group = null;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private String namePrefix = null;
{
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "prac-" +
poolNumber.getAndIncrement() +
"-thread-";
}
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
);
while (true){
Thread.sleep(100);
threadPool.submit(()-> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("zssmb");
});
}
}
}
线程同步类
- CountDownLaunch (减法器、门栓)
public class PracCountDownLaunch {
public static void main(String[] args) throws InterruptedException {
//创建新的线程池
ScheduledExecutorService sc = Executors.newScheduledThreadPool(10);
//门栓
final CountDownLatch downLatch = new CountDownLatch(5);
for (int i = 0; i < 10; i++) {
ThreadUtil.sleep(100);
int finalI = i;
sc.submit(()->{
ThreadUtil.sleep(100);
System.out.println(finalI);
ThreadUtil.sleep(100);
downLatch.countDown();
});
}
//CountDownLatch等待downLaunch减为0 再往后执行
downLatch.await();
System.out.println("执行总任务");
sc.shutdown();
}
}
- CyclicBarrier (循环栅栏)
public static void main(String[] args) throws BrokenBarrierException, InterruptedException {
//创建线程池
ScheduledExecutorService service = Executors.newScheduledThreadPool(5);
//最终所要完成的任务
Runnable main = ()-> System.out.println("总报表");
//创建循环栅栏
CyclicBarrier cy = new CyclicBarrier(2,main);
Runnable tesk = ()-> {
System.out.println("abc");
try {
cy.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
};
for (int i = 0; i < 2; i++) {
service.submit(tesk);
ThreadUtil.sleep(100);
}
System.out.println("--------------------");
//重用cy栅栏
cy.reset();
for (int i = 0; i < 2; i++) {
service.submit(tesk);
ThreadUtil.sleep(100);
}
service.shutdown();
}
- Semaphore (信号量)
一次最多允许5此获取令牌
public static void main(String[] args) throws BrokenBarrierException, InterruptedException {
//创建线程池
ScheduledExecutorService service = Executors.newScheduledThreadPool(5);
//最终所要完成的任务
Runnable main = ()-> System.out.println("总报表");
//信号量
Semaphore semaphore = new Semaphore(5);
//创建一个原子类
AtomicInteger j = new AtomicInteger(0);
Runnable tesk = ()-> {
try {
//获取令牌
semaphore.acquire();
ThreadUtil.sleep(1000);
System.out.println(j.getAndIncrement());
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//释放令牌
semaphore.release();
}
};
for (int i = 0; i < 10; i++) {
service.submit(tesk);
}
service.shutdown();
}
单例的各种实现
1、饿汉式
public class ESingleton {
//饿汉式
private static ESingleton singleton = new ESingleton();
private ESingleton() {
}
public static ESingleton getSingleton() {
return singleton;
}
}
2.懒汉式:
public class LSingleton {
//懒汉式
private static LSingleton singleton;
private LSingleton(){}
//线程不安全
public static LSingleton getSingleton1() {
if (singleton == null){
singleton = new LSingleton();
}
return singleton;
}
//线程安全 双重锁模式 双重检查
public static LSingleton getSingleton2() {
if (singleton == null){
synchronized (LSingleton.class){
if (singleton == null){
singleton = new LSingleton();
}
}
}
return singleton;
}
}
3.静态内部类实现:(常用)
public class StaticSingleton {
//静态内部类单例模式
private StaticSingleton(){}
public static StaticSingleton getInstance(){
return Inner.singleton;
}
private static class Inner{
private static final StaticSingleton singleton = new StaticSingleton();
}
}