这是自己写的第一篇关于Java学习的博客,准确的说是将网上一些大佬的文章整合一下,是一篇知识总结性的文章。初学者,只是为了了解一些Java多线程的基础知识,以后再完善。
基础概念
线程
线程和进程类似,线程是比进程更小的可执行单位。一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源
多线程
就是多个线程同时运行或交替运行。单核cpu的话是顺序运行,也就是交替运行。多核cpu的话,因为每个cpu都有自己的运算器,所有在多个cpu中可以同时运行
同步和异步
同步方法调用,调用者必须等到方法调用返回后,才能继续后续的行为,在我的理解里,一个典型的例子就是函数
异步方法调用更像消息传递一样,一旦开始,方法调用后就会立即返回,调用者可以继续进行后面的行为
并发(Concurrency)和并行(Parallelism)
他们两个都可以表示多个任同时进行,但偏重不同,并发偏重于多个任务交替执行,而多个任务之间有可能还是串行。
并行是真正意义上的同时进行
Java中线程的创建
继承Thread类,重写该类的run()方法
public Class MyThread extends Thread{
public void run(){
//代码
}
}
Run.java
public class Run {
public static void main(String[] args){
MyThread mythread = new MyThread();
mythread.start();
}
}
实现Runnable()接口,重写该类的run()方法
public class MyRunnable implements Runable{
public void run(){
//代码
}
}
Run.java
public class Run{
public static void main(String[] args){
Runnable runnable = new MyRunnable();
Thread thread = new Thread(runnable);
thread.start();
}
}
synchronized 同步锁(理解的难点)
每一个java对象都有一个监视器,来监测并发代码的重入,在此块内,监视器 monitor 发挥作用
使用Synchronized方法来对对象进行加锁
synchronized(obj){
//同步代码块
}
在执行同步代码块之前,必须获得对同步监视器的锁定。任何时刻都只有一个进程能获得同步监视器的锁定,当同步代码块执行完成的时候,该线程会释放掉对同步监视器的锁定。理解一下下面的这段代码
/**
* java多线程中锁的使用,wait(),notify()方法的使用
* 经典面试题目: 建立三个线程,A线程打印10次A,B线程打印10次B,C线程打印10次C,要求线程同时运行,交替打印10次ABC。
*/
public class SynchronizedDemo implements Runnable{
private String name;
private Object prev;
private Object self;
public SynchronizedDemo(){}
public SynchronizedDemo(String name,Object prev,Object self){
this.name=name;
this.prev=prev;
this.self=self;
}
// MIN_PRIORITY = 1
// NORM_PRIORITY = 5
// MAX_PRIORITY = 10
@Override
public void run() {
int i=0;
while(i<10){
synchronized (prev) {
synchronized (self) {
self.notify(); //唤醒当前进程
System.out.print(name);
i++;
}
try {
prev.wait(); //让前置进程wait
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws Exception {
Object a=new Object();
Object b=new Object();
Object c=new Object();
SynchronizedDemo pa=new SynchronizedDemo("A", c, a);
SynchronizedDemo pb=new SynchronizedDemo("B", a, b);
SynchronizedDemo pc=new SynchronizedDemo("C", b, c);
new Thread(pa).start();
Thread.sleep(100);
new Thread(pb).start();
Thread.sleep(100);
new Thread(pc).start();
Thread.sleep(100);
}
}
常用的函数说明
wait()
运行的进程执行wait方法,JVM会把该线程放入等待池中(wait会释放持有的锁)--等待阻塞
join()
如果某个线程J在另一个线程T上调用T.join(),那么此线程(J)将会被挂起,直到目标线程T结束才恢复
为什么要使用join()方法?
在很多情况下,主线程生成并带动了子线程,如果子线程耗时很长的话,主线程可能要比子线程先结束。但是如果需要主线程在子线程之后结束的话,就需要用到join() 方法。
class Thread1 extends Thread{
private String name;
public Thread1(String name){
super(name);
this.name=name;
}
public void run(){
System.out.println(Thread.currentThread().getName()+"线程运行开始!");
for (int i=0;i<5;i++){
System.out.println("子线程"+name+i);
try{
sleep((int)Math.random()*10);
}catch (InterruptedException e){
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"线程运行结束!");
}
}
public class Join {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName()+"主线程开始运行!");
Thread mth1 = new Thread1("A");
Thread mth2 = new Thread1("B");
mth1.start();
mth2.start();
//如果不加下面的代码的话,主线程就会在子线程之前结束
try{
mth1.join();
}catch (InterruptedException e)
{
e.printStackTrace();
}
try{
mth2.join();
}catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"主线程运行结束!");
}
}
yield()
暂停当前的正在执行的线程对象,并执行其他线程
notify() notifyAll()
唤醒线程 唤醒后进入锁定状态 在获得同步锁(synchronized )之后才会进入运行状态
Blocked(阻塞状态): 由于某些原因,该线程放弃了对cpu的使用权。根据阻塞产生的原因,可以把阻塞分为一下三类:
1.等待阻塞:线程执行wait()方法,使该线程进入到等待阻塞状态
2.同步阻塞:线程在获取sychronized同步锁时出错(其他线程在占有该同步锁)
3.其他阻塞:通过调用该线程的sleep()或join()或发起了I/O请求