进程:是一个正在执行的程序。
每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。
线程:就是进程中的一个独立的控制单元,线程在控制着进程的执行。
一个进程中至少有一个线程。
Java虚拟机启动的时候会有一个进程java.exe,该进程中至少一个线程负责java程序的执行。
而且这个线程运行的代码存在于main方法中,该线程成为主线程。
更细节的说明jvm,jvm启动不止一个线程,还有负责垃圾回收机制的线程。
创建线程:
第一种方式,继承Thread类
1. 定义类继承Thread类
2. 复写Thread类中的run()方法
目的:将自定义代码存储在run方法中,让线程运行
3. 调用线程的start()方法,该方法有两个作用:启动线程,调用run方法。
class demo extends Thread
{
publicvoid run()
{
}
}
多线程的一个特性:随机性,那个线程抢到cpu执行权,哪个就先执行。
线程都有自己默认的名称,通过getName()方法获取,名称是Thread-编号,该编号从0开始。
Thread类的方法:
构造方法设置线程名称:Thread(Stringname),子类直接调用就可以,
classTest extends Thread
{
Test(Stringname)
{
super(name);
}
public voidrun()
{
System.out.println(Thread.currentThread().getName());
}
}
class demo{
publicstatic void main(String []args){
Ttestt1 = new Test(“one”);
Testt2 = new Test(“two”);
t1.start();
t2.start();
}
}
getName()获取线程名称
currentThread()返回当前线程对象,static Thread Thread.currenThread()
第二种方式:实现Runnable接口
1. 定义类实现Runnnable接口
2. 覆盖Runnnable接口中的run方法
3. 通过Thread类建立线程对象
4. 将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
自定义的run方法所属的对象是Runnable接口的子类对象,要让线程去指定指定对象的run方法,就必须明确该run方法所属对象
5. 调用Thread类的start方法启动线程并调用Runnable接口子类的run方法
class Test implements Runnable
{
publicvoid run()
{
System.out.println();
}
}
class demo
{
publicstatic void main()
{
Testt = new Test();
Threadt1 = new Thread(t);
Threadt2 = new Thread(t);
t1.start();
t2.start();
}
}
实现方式和继承方式的区别:
实现方式好处:避免了单继承的局限性。
在定义线程时,建议使用实现方式。
class Test implements Runnable
{
privateint ticket = 100;
publicvoid run()
{
while(true)
{
if(ticket>0) //这里会出现安全问题
{
try{Thread.sleep(10);}catch(Exceptione){}
System.out.println(currentThread().getName()+”….”+ticket--);
}
}
}
}
class demo
{
publicstatic void main()
{
Testt = new Test();
Threadt1 = new Thread(t);
Threadt2 = new Thread(t);
Threadt3 = new Thread(t);
Threadt4 = new Thread(t);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
多线程的运行出现安全问题:
问题原因:当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行,导致共享数据的错误。
解决:同步代码块
synchronized(对象)
{
需要被同步的代码
}
对象如同锁,持有锁的线程可以在同步中执行。
没有持有锁得线程即使获得cpu的执行权,也进不去,因为没有获取锁
前提:必须是多个线程使用同一个锁
必须要有两个或两个以上的线程
Object obj = new Object();
synchronized(obj)
{
if(ticket>0)
{
try{Thread.sleep(10);}catch(Exceptione){}
System.out.println(currentThread().getName()+”….”+ticket--);
}
}
同步有两种表现形式,一种是同步代码块,一种是同步函数
比如:publicsynchronized void add(int n)
{
Sum= sum+n;
System.out.println(sum);
}
同步函数用的锁:
函数需要被对象调用,那么函数都有一个所属对象引用,this,所以同步函数使用的锁就是this。
静态同步方法使用的锁是该方法所在类的字节码文件对象。 类名.class
懒汉式
class Single
{
privatestatic Single = null;
privateSingle(){}
publicstatic void getInstance()
{
if(s==null)
{
synchronized(Single.class)
{
If(s==null)
{
s = new Single();
}
}
}
return s;
}
}
死锁:同步中嵌套同步
class Test implements Runnable
{
privateboolean flag;
Test(booleanflag)
{
this.flag= flag;
}
publicvoid run()
{
if(flag)
{
synchronized(Mylock.locka)
{
System.out.println("iflocka");
synchronized(Mylock.lockb)
{
System.out.println("iflockb");
}
}
}
else
{
synchronized(Mylock.lockb)
{
System.out.println("elselockb");
synchronized(Mylock.locka)
{
System.out.println("elselocka");
}
}
}
}
}
class Mylock
{
staticObject locka = new Object();
staticObject lockb = new Object();
}
class sisuo{
publicstatic void main(String []args){
Threadt1 = new Thread(new Test(true));
Threadt2 = new Thread(new Test(false));
t1.start();
t2.start();
}
}