进程:
正在运行的程序。代表着一个应用程序的内存空间。
在该空间中需要对该应用程序的代码进行执行控制。
每一个控制代码执行流程的单元称为线程
线程:
是进程中一个独立的控制单元,也称为执行路径,执行情景,一个进程中至少有一个线程
Jvw虚拟机在执行一个java程序时,至少启动了了两个线程;
一个是主线程,该线程执行的是main函数中的代码
另一个是垃圾回收线程,执行垃圾回收的代码;
多线程技术可以有多个执行路径,让多部分代码实现同时执行(单核的CPU,执行过程中其实是在做着快速的切换)
创建线程的方式:
一:继承Thread类
1 定义类继承Thread类,作为线程类的子类
2 定义线程要运行的代码,并将代码存储到Thread类的run方法中
(主线程要运行的代码定义在main函数中,自定义要运行的代码定义在run方法中)
3 调用线程类的start方法开启线程,并执行线程的run方法
运行时会发现结果每一次都有可能不一样。那是因为cpu在做着快速切换完成的,执行过程中,是按照cpu的特点执行,没有什么规则,所以,多线程运行时,有一个特性:随机性。线程有自己默认的名称Thread-编号,从0开始编号可以通过Thread类中的方法进行获取:
static Thread currentThread():返回当前线程对象。
String getName():获取线程对象的名称。
class Demo extends Thread{
private String name;
Demo(String name){
this.name = name;
}
public void run(){
for(int x=0; x<30; x++){
for(long y=-9999990; y<100000000; y++){}
System.out.println(name+"。。。"+x+"...."+Thread.currentThread().getName());
}
}
}
class ThreadDemo {
public static void main(String[] args) {
Demo d1 = new Demo("one---");
Demo d2 = new Demo("two");
d1.start();
d2.start();
for(int x=0; x<30; x++){
System.out.println("hello main....."+x+"...."+Thread.currentThread().getName());
}
}
}
二 、实现Runnable接口
定义类实现Runnable接口
覆盖Runnable接口中的run方法,将多线程要运行的代码存放该run方法中
通过Thread类创建线程对象
将实现了Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。
为什么要将Runnable接口的子类对象作为参数传递呢?
是为了告诉多线程要运行的代码所属的对象。调用Thread类的start方法让线程启动并运行。
class Demo implements Runnable{
private String name;
Demo(String name){
this.name = name;
}
public void run(){
for(int x=0; x<30; x++){
for(long y=-9999990; y<100000000; y++){}
System.out.println(name+"。。。"+x+"...."+Thread.currentThread().getName());
}
}
}
class ThreadDemo {
public static void main(String[] args) {
Demo d1 = new Demo("one---");
Demo d2 = new Demo("two");
Thread t1= new Thread(d1);
Thread t2= new Thread(d2);
t1.start();
t2.start();
for(int x=0; x<30; x++){
System.out.println("hello main....."+x+"...."+Thread.currentThread().getName());
}
}
}
继承Thread类和实现Runnable接口的区别:
实现Runnable接口可以避免单继承的局限性
所以,在创建线程是建议使用第二种方式
其实该接口在设计时,就是将线程要运行代码的位置进行抽取
线程安全问题产生的原因:
当多个线程对操作共性数据的多句代码分开执行导致的
要素: 共性数据、 多句操作共性数据的代码
解决该问题的原理:
保证多条操作共性数据的代码在同一时间段只有一个线程在执行,在执行期间,不允许其他线程参与
解决方式:Java提供了解决方案,就是同步机制。
代码体现:同步代码块。
Synchronized(任意对象){
//需要被同步封装的语句
}
同步好处:解决了多线程的安全问题
同步前提:
1 必须要有两个或者两个以上的线程。
2 多个线程必须使用同一个锁
如果加上同步问题没被解决就是前提出错
同步弊端:
降低运行效率,对资源是一种消耗。
同步代码块是一个封装体,函数也是一个封装体,如果让函数具备了同步性,那么就没有必要定义同步代码块了。这个函数就称为同步函数。
同步函数锁使用的锁是this
同步函数和同步代码块的区别:
同步函数使用的锁是固定的this
同步代码块可以指定任意的对象作为锁
一般开发常用同步代码块
静态同步函数所使用的锁是:所属类的字节码文件对象,写法是类名.class
死锁:在同步嵌套的时候,容易出现死锁
要尽量避免死锁。