/**
* 进程:正在进行中的程序(直译)
* 线程:进程中一个负责程序执行的控制单元(执行路径)
* 一个进程中可以多执行路径,称之为多线程
* 一个进程中至少有一个线程
* 开启多个线程是为了同时运行多部份代码。
* 每一个线程都有自己运行的内容。这个内容可以称之为线程要执行的任务。
*/
//系统垃圾处理
/**
* 其实应用程序的执行都是cpu在做着快速的切换完成的。这个切换是随机的。
* JVM启动时就启动了多个线程,至少有两个线程可以分析得出来。
* 1.执行main函数的线程
* 2.负责垃圾回收的线程
* 代码在垃圾回收器里面定义
*/
class G extends Object{
public void finalize(){//类的回收方法
System.out.println("object garbage clone");
}
}
public class packDemo{
public static void main(String[] args){
new G();
new G();
System.gc();//系统垃圾回收
new G();
System.out.println("gello");
}
}
//运行结果:
//gello
//object garbage clone
多线程
继承Thread类
/**
* 如何创建一个线程
* 创建线程方式一:继承Thread类。
* 步骤:
* 1,定义一个类继承Thread类。
* 2,覆盖Thread类中的run方法。
* 3,直接创建Thread类的子类对象
* 4,调用start方法开启线程并调用线程的任务
* 可以通过Thread.getName()获取线程名字
*/
class G extends Thread{
private String name;
G(String name){
this.name = name;
}
public void run(){
show();
}
public void show(){
for(int i=0;i<10;i++){
System.out.println(this.name+"...i = "+i);
}
}
public void finalize(){//类的回收方法
System.out.println("object garbage clone");
}
}
public class packDemo{
public static void main(String[] args){
// Thread t1 = new Thread();//创建线程
/**
* 创建线程的目的是开启一条执行路径,运行指定的代码和其他代码同时运行。
* 而运行的指定代码就是这个执行路径的任务
* jvm创建的主线程的任务都定义在主函数中。
* 自定义线程的任务:
* Thread类用于描述线程,run方法封装自定义线程运行任务的函数。
*/
G g1 = new G("g1");
G g2 = new G("g2");
g1.start();//调用run方法
g2.start();
System.gc();//系统垃圾回收
System.out.println(4/0);
for(int i=0;i<20;i++){
System.out.println("gello.."+i+"..."+Thread.currentThread().getName());
}
}
}
实现Runable接口
/**
* Thread类不能和其他类同时被继承
* 创建线程的第二种方式:实现Runable接口
* 1.定义类实现Runable接口
* 2.覆盖接口中的run方法,将线程的任务代码封装到run方法中
* 3.通过Thread类创建线程对象,并将Runable接口的子类对象作为构造函数的参数进行传递
* 为什么?
* 因为线程的任务都封装在Runable接口子类对象的run方法中
* 所以要在线程对象创建时就必须明确要运行的任务
* 4.调用线程对象的start方法开启线程
*
* 实现Runable接口和继承Thred的区别:
* 1.实现Runable将线程的任务从线程的子类中分离出来进行了单独封装。
* 按照面向对象的思想将任务封装成对象
* 2.实现Runable避免了java单继承的局限性
*/
class Fu{
public void show(){}
}
class G extends Fu implements Runnable{//通过扩展G类的功能,让其中的内容可以作为线程的任务执行。
//通过接口的形式完成
private String name;
G(String name){
this.name = name;
}
public void run(){
show();
}
public void show(){
for(int i=0;i<10;i++){
System.out.println(this.name+"... = "+i+"..."+Thread.currentThread().getName());
}
}
}
public class packDemo{
public static void main(String[] args){
G g1 = new G("g1");
Thread t1 = new Thread(g1);
Thread t2 = new Thread(g1);
t1.start();
t2.start();
}
}
//Thread类架构
class Thread{
private Runnable r;
Thread(){}
Thread(Runnable r){
this.r = r;
}
public void run(){
if(r!=null)
r.run();
}
public void start(){
run();
}
}
多线程:卖票示例
/**
* 线程安全问题产生的原因:
* 1.多个线程在操作共享的数据
* 2.操作共享数据的代码有多条
* 当一个线程在执行操作共享数据的代码时,其他线程参与了运算。就会导致线程安全问题的产生。
*
* 解决方式:
* 将多条操作共享数据的代码封装起来,当有线程在执行代码时,其他线程不能参与运算,
* 必须要当前线程将代码执行完毕后,其他线程才可以参与运算。
*
* 在java中用同步代码块:
* synchronized(对象)
* {需要被同步的代码;}
*
* 同步的好处:解决了线程的安全问题
* 同步的弊端:相对降低了效率,因为同步外的线程都会判断同步锁
* 同步的前提:同步中必须有多个线程并使用同一同步锁
*/
class Ticket implements Runnable{
private int num = 100;
Object obj = new Object();
public void run(){
while(true){
synchronized(obj)
{
if(num>0){
try{Thread.sleep(10);}catch(InterruptedException e){}
System.out.println(Thread.currentThread().getName()+"...sale..."+num--);
}
}
}
}
}
public class packDemo{
public static void main(String[] args){
Ticket t = new Ticket();//创建一个线程任务对象
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
Thread t3 = new Thread(t);
Thread t4 = new Thread(t);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
同步函数
/**
* 需求:两个储户,每个都到银行存钱,每次存100,共存三次
*/
/**
* 同步函数使用的锁是this,
* 同步函数和同步代码块的区别:
* 同步函数的锁是固定的this。
* 同步代码块的锁是任意的对象。
* 建议使用同步代码块
*/
class Bank{
private int sum;
Object obj = new Object();
//直接同步函数
public synchronized void add(int num){
sum = sum+num;
System.out.println("sum = "+sum);
}
/*
public void add_code(int num){
synchronized(obj){
sum = sum+num;
System.out.println("sum = "+sum);
}
}
*/
}
class Cus implements Runnable{
Object obj = new Object();
Bank b = new Bank();
public void run(){
for(int i=0;i<3;i++){
b.add(100);
}
}
}
public class packDemo{
public static void main(String[] args){
Cus c = new Cus();
Thread t1 = new Thread(c);
Thread t2 = new Thread(c);
t1.start();
t2.start();
}
}
//public static synchronized void show(){}
//静态方法中没有this,锁是该函数(当前class文件)所属的字节码文件对象(对象)用:this.getClass() or 类名.class表示
单例设计模式涉及的多线程问题
//
//饿汉式
class Single{
private static final Single s = new Single();
private Single(){}
public static Single getInstance(){
return s;//用到相同数据s的代码只有一条,不用加锁
}
}
//懒汉式
class Single_lazy{
private static Single_lazy s = null;
private Single_lazy(){}
public static Single_lazy getInstance(){
if(s==null){//双重判断,为了减少锁判断,提高效率
synchronized(Single_lazy.class){
if(s==null){
s = new Single_lazy();
}
}
}
return s;
}
}
死锁示例
/**
* 死锁示例
* 常见情形之一:同步的嵌套
*/
class Test implements Runnable{
private Boolean flag;
Test(Boolean flag){
this.flag = flag;
}
public void run(){
if(flag){
synchronized(MyLock.locka){
System.out.println("if....locka");
synchronized(MyLock.lockb){
System.out.println("if....lockb");
}
}
}
else{
synchronized(MyLock.lockb){
System.out.println("else....lockb");
synchronized(MyLock.locka){
System.out.println("else....locka");
}
}
}
}
}
class MyLock{
public static Object locka = new Object();
public static Object lockb = new Object();
}
public class packDemo{
public static void main(String[] args){
Test a = new Test(true);
Test b = new Test(false);
Thread t1 = new Thread(a);
Thread t2 = new Thread(b);
t1.start();
t2.start();
}
}