进程:正在进行的程序。每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元。
线程:进程内部的一条执行路径或者一个控制单元。
两者的区别: 一个进程至少有一个线程, 进程在执行过程中拥有独立的内存单元,而多个线程共享内存。
(1)继承Thread
步骤:1.定义一个线程类继承Thread
2.复写Thread类中的run方法==>将自定义代码存储在子类run方法中,让子线程运行。
3.调用线程的Thread方法==>两个作用:启动线程&调用run方法
为什么运行结果每次都不同?
因为多个线程都获取CPU的执行权,CPU执行到谁,谁就运行。需要注意的是:在某一个时刻,
只能有一个程序在运行。(多核CPU除外) 只不过是CPU在做着快速切换,已达到看上去是同时运行的效果。
我们可以形象的把多线程的运行看作是在互相抢夺CPU的执行权。
这是CPU的一个特性:随机性。谁抢到CPU的资源谁就执行,至于运行多长时间,CPU说了算。
为什么要覆盖Run方法? Thread类用于描述线程。该类就定义了一个功能,用于存储线程要运行的代码,该存储功能就是run方法。
start()和run()方法有什么区别?
调用start方法方可启动线程,而run方法只是thread的一个普通方法,调用run方法不能实现多线程。
start()方法:
start()方法用来启动线程,实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码。通过调用Thread类的start()方法来启动一个 线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片(执行权),就开始执行run()方法,这里方法run()称为线程体,它包含了要执行的这个 线程的内容,Run方法运行结束,此线程随即终止。
run()方法:
run()方法只是Thread类的一个普通方法,如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要等待run方法体执 行完毕后才可继续执行下面的代码,这样就没有达到多线程的目的。
class Demo extends Thread
{
private String name;
Demo(String name)
{
this.name = name;
}
public void run()
{
for(int i=0 ; i<50 ; i++)
System.out.println("No."+name +" SubThread running===>"+i);
}
}
public class ThreadIntro
{
public static void main(String[] args)
{
Demo d1 = new Demo("1");//创建好一个线程
d1.start();//开启线程并执行该线程的run方法
Demo d2 = new Demo("2");
d2.start();
//d.run();//仅仅是对象调用方法。并没有使用创建的线程
for(int i=0 ; i<50 ; i++)
System.out.println("MainThread running--->"+i);
}
}
(2)实现Runnable接口;
定义一个类,实现Runnable接口;
覆盖接口的public void run()的方法,将线程的任务代码封装到run方法中;
创建Runnable接口的子类对象
将Runnabl接口的子类对象作为参数传递给Thread类的构造函数,创建Thread类对象 调用start()方法,启动线程。
class bank
{
private int total;
public synchronized void add(int num)
{
total += num;
try
{
Thread.sleep(10);
}
catch (Exception e)
{
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" Total:"+total);
}
}
class client implements Runnable
{
private bank b = new bank();
public void run()
{
for(int i = 0 ; i < 3 ; i++)
{
b.add(100);
}
}
}
public class ThreadBankDemo
{
public static void main(String[] args)
{
client c = new client();
Thread t1 = new Thread(c);
Thread t2 = new Thread(c);
t1.start();
t2.start();
new Thread(c).start();
}
}
3.多线程的单例设计模式:
饿汉式是类一加载进内存就创建好了对象。
//饿汉式单例加锁(General used in coding)
class Singlee
{
private static final Singlee s = new Singlee();
private Singlee(){}
public static Singlee getInstance()
{
return s;
}
}
懒汉式则是类加载进内存的时候,对象还没有存在,只有调用了getInstance()方法时,对象才开始创建。懒汉式是延迟加载,如果多个线程同时操作懒汉式时就有可能出现线程安全问题,解决线程安全问题可以加同步来解决。
class Single
{
private Single(){}
private static Single s;
public static Single getInstance()
{
if(s==null)
s=new Single();
return s;
}
}
但是加了同步之后,每一次都要比较锁,效率就变慢了,所以可以加双重判断来提高程序效率。如将上述懒汉式的Instance函数改成同步:
//懒汉式单例加锁(延迟加载模式)
class Single
{
private static Single s = null;
private Single(){}
public static Single getInstance()
{
if(s==null)
{
synchronized(Single.class)//锁为该类所属的字节码类对象
{
if(s==null)
s = new Single();
}
}
return s;
}
}