1.概念
(1)程序
程序是为完成特定任务,用某种语言编写的一组指令的集合。即一组静态的代码。(编译好的二进制文件,放在磁盘上)
(2)进程
进程是计算机中正在运行的程序,如运行中的QQ,微信等。(进程是操作系统进行资源分配的最小单位)
(3)线程
进程可以细化为一个线程,线程是一个进程内部的最小执行单元,是操作系统进行任务调度的最小单元。(例如:当启动QQ时可以同时开启多个聊天窗口,这些聊天窗口就是线程)
(4)进程与线程的关系
1.一个进程可以有多个线程。
2.一个线程只属于一个进程。(例如:QQ里的聊天窗口只属于QQ进程,不属于微信进程)
3.一个进程至少有一个线程,称为主线程。(例如:例如:启动QQ时至少有一个聊天窗口)
4.在主线程中可以创建并启动其它的线程;
5.一个进程内的所有线程共享该进程的内存资源。
2.线程的创建
(1)单线程
一般程序都是按照调用顺序依次往下执行的,不会出现交替执行的情况,如果要出现程序交替的情况,就要实现多线程,多线程就是一个进程在执行过程中可以实现多个线程,多个线程运行时是相互独立的。
例如:
package XC;
public class DXC {
public void run()
{
for (int i = 0; i <100 ; i++) {
System.out.println("run");
}
}
}
package XC;
public class TestDXC {
public static void main(String[] args) {
DXC dxc=new DXC();
dxc.run();
for (int i = 0; i < 100; i++) {
System.out.println("main"+i);
}
}
}
上述代码run方法里的程序执行完后才会执行main。单线程按顺序执行。
(2)创建方式1:继承Thread类
package XC;
public class Thread1 extends Thread{
@Override
public void run() {//重写了Thread的run方法,run方法相当于继承了Thread子类要执行的任务
for (int i = 0; i < 100; i++) {
System.out.println("run:"+i);
}
}
}
package XC;
public class TestThread {
public static void main(String[] args) {
Thread1 thread1=new Thread1();//创建实例Thread1对象
thread1.start();//启动线程
for (int i = 0; i < 100; i++) {
System.out.println("main:"+i);
}
}
}
如图多线程不是按照程序执行顺序执行的,顺序不固定,main线程和继承了Thread类的Thread1类执行顺序不一定,两个线程是相互独立的,执行顺序取决于CUP的性能,和计算机相应的硬件。
(2)创建方式2:实现Runnable接口
package ThreatTicket;
public class RunnaberTicket implements Runnable{
int num=10;
@Override
public void run() {
while (true) {
synchronized (this) {//给当前线程加锁,让窗口一和窗口二各自独立买票
if (num > 0) {
try {
Thread.sleep(500);//让当前正在运行的线程停止500微秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "买到的是第" + num + "张票");
num--;
} else
break;
}
}
}
}
package ThreatTicket;
import sun.swing.AccumulativeRunnable;
public class TestRunnable {
public static void main(String[] args) {
//线程执行的任务执行了两次,只创建了一个任务对象,与继承了Thread的类不同
RunnaberTicket runnable=new RunnaberTicket();
Thread thread=new Thread(runnable);
thread.setName("窗口一");
thread.start();
Thread thread1=new Thread(runnable);
thread1.setName("窗口二");
thread1.start();
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/3fe76b279a054ad9d82602bae7b2d1ff.png)
package ThreatTicket;
import com.sun.deploy.security.SelectableSecurityManager;
public class Ticket extends Thread{
static int num=10;//static修饰的变量静态变量,只有一份
static Object object=new Object();//synchronized同步锁的对象,同步锁的对象必须是唯一的
@Override
public void run() {
while (true)
{ synchronized (object)
{ if(num>0)
{
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"买到的是第"+num+"张票");
num--;
}
else
break;
}}
}
}
package ThreatTicket;
public class TestTicket {
public static void main(String[] args) {
Ticket ticket=new Ticket();
ticket.setName("窗口1");
ticket.start();
Ticket ticket1=new Ticket();
ticket1.setName("窗口2");
ticket1.start();
}
}
3.线程同步
(1)线程同步就是排队加锁,多个线程同时读写同一份共享资源时,可能会引起冲突。所以引入线程“同步”机制, 即各线程间要有先来后到;
几个线程之间要排队,一个个对共享资源进行操作,而不是同时进行操作, 为了保证数据在方法中被访问时的正确性,在访问时加入锁机制。
举例:下述代码是实现Runnable接口的买票,与上述第二个创建线程二的实现Runnable接口的买票一样,只不过在run方法中线程共享的买票没加synchronized,即为没加锁,这两个线程就会同时进到买票中,会导致两个线程买到同一张票,或者买到零张票,
package ThreatTicket;
public class RunnaberTicket implements Runnable{
int num=10;
@Override
public void run() {
while (true) {
if (num > 0) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "买到的是第" + num + "张票");
num--;
} else
break;
}
}
}
package ThreatTicket;
import sun.swing.AccumulativeRunnable;
public class TestRunnable {
public static void main(String[] args) {
RunnaberTicket runnable=new RunnaberTicket();
Thread thread=new Thread(runnable);
thread.setName("窗口一");
thread.start();
Thread thread1=new Thread(runnable);
thread1.setName("窗口二");
thread1.start();
}
}