zoukankan      html  css  js  c++  java
  • java 多线程

    java多线程

    关于内存

    每个线程会有自己的线程栈,即,变量不能共享,只能传值拷贝
    每个线程new出的对象全都保存在堆中,全部共享

    线程的生命周期

    线程具有5种状态,即新建,就绪,运行,阻塞,死亡。
    新建,当new出来一个线程以后,jvm为其分配内存空间,并初始化成员变量的值
    就绪,当线程调用了strat()方法的时候,线程就绪,会为其创建方法调用栈和程序计数器。

    方法调用栈 即,记录方法调用的次数
    程序计数器 存放下一条单元指令的地方

    运行;就绪状态获得cpu,开始执行run()方法
    阻塞:例如进入I/O操作

    新建,就绪

    使用new关键字创建一个线程以后,该线程处于新建状态,和其他java线程一样,仅仅由java虚拟机为其分配内存,初始化变量成员的值。

    运行和阻塞

    线程调度

    桌面和服务器使用抢占式调度策略,小型设备使用协作式调度策略,

    线程阻塞

    线程使用sleep()方法主动放弃所占用的处理器资源。
    线程调用阻塞式I/O方法,方法被返回前,阻塞
    线程等待通知
    线程调用suspend()挂起

    解除阻塞

    依依对应即可

    线程优先级

    普通5,低1,高10
    默认是5

    关于start和run

    start创建一个线程,由于是时间片运行的,所以需要run方法进行运行。
    总结
    start创建线程,run方法运行线程。

    创建线程

    使用Thread继承类实现创建线程

    文档 https://docs.oracle.com/javase/8/docs/api/
    该类必须重写run方法。为新线程的入口点。
    必须调用start()方法才能运行。

    本质上是Runnable接口的一种实现

    package demo2;
    
    public class test {
    	public static void main(String[] args) {
    		// 创建一个线程
    		ThreadDemo run1 = new ThreadDemo();
    		run1.start();// 启动线程
    		// 在运行线程以后,会不定时的jvm调用run方法,进行运行
    	}
    }
    
    package demo2;
    
    public class ThreadDemo extends Thread{
    	public ThreadDemo() {
    		System.out.println("hello world");
    	}
    	
    	public void run() {
    		System.out.println("线程进入");
    		for(int i = 0; i > 10; i++) {
    			System.out.println("输出内容");
    		}
    		System.out.println("线程执行完毕");
    	}
    }
    
    

    事实上父类的start方法也可以重写

    package demo2;
    
    public class ThreadDemo extends Thread{
    	public ThreadDemo() {
    		System.out.println("hello world");
    	}
    	
    	public void run() {
    		System.out.println("线程进入");
    		for(int i = 0; i > 10; i++) {
    			System.out.println("输出内容");
    		}
    		System.out.println("线程执行完毕");
    	}
    	
    	public void start() {
    		System.out.println("启动线程");
    		this.run();
    	}
    }
    

    然后测试类

    package demo2;
    
    public class test {
    	public static void main(String[] args) {
    		// 创建一个线程
    		ThreadDemo run1 = new ThreadDemo();
    		run1.start();// 启动线程
    	}
    }
    

    Thread方法

    public final void setDaemon(boolean on)

    用于标记守护线程和用户线程
    用户线程,平常创建的普通线程
    守护线程,服务于用户线程,不需要上层调用,例如gc垃圾回收为一个明显的守护线程,mysql中也有执行定时任务的线程。

    中断线程

    它表示一个线程被中断,会抛出错误。

    使用Runnable接口

    文档https://docs.oracle.com/javase/8/docs/api/
    属于java.lang包内的,为自动默认加载的
    该接口具有一个run方法,run方法为程序的入口
    必须通过Thread类的构造方法实现启动线程

    package demo2;
    
    public class test {
    	public static void main(String[] args) {
    		// 创建一个线程
    		demoRunnable r1 = new demoRunnable();
    		// 使用Thread类的构造方法传入线程,并起名,然后运行
    		new Thread(r1, "name").start();// 创建完成线程以后,调用start启动线程
    	}
    }
    
    package demo2;
    
    public class demoRunnable implements Runnable{
    	private int i;
    
    	// 下方的为运行的线程
    	@Override
    	public void run() {
    		for(int i = 0; i < 100; i++) {
    			System.out.println("运行线程 " + i);
    		}
    	}
    }
    

    通过Callable和Future来创建线程

    使用Callable创建接口的实现类
    接口源码如下

    @FunctionalInterface
    public interface Callable<V> {
        V call() throws Exception;
    }
    

    实现了一个泛型,该并且返回该类型,需要实现call方法。使用包装对象

    关于包装类型,即,将不是对象的内容包装成为对象,为包装类型,实现了对象的类型,为一个类

    先实现Callable接口,其中的call类为程序的子线程的执行体

    package demo2;
    
    import java.util.concurrent.Callable;
    
    public class CallableDemo implements Callable<Integer>{
    	@Override
    	public Integer call() throws Exception {
    		System.out.println("开始运行一个线程");
    		for(int i = 1, i < 10; i++) {
    			System.out.println("运行中");
    		}
    		// 阻塞该线程
    		Thread.sleep(200);
    		return 1;	// 返回线程的值
    	}
    }
    

    接着创建Future对象,将用于启动子线程

    package demo2;
    
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.FutureTask;
    
    public class test {
    	public static void main(String[] args) {
    		// 先创建实例
    		CallableDemo ctt = new CallableDemo();
    		FutureTask<Integer> ft = new FutureTask<>(ctt);	// 该方法为了获取返回值而设定	
    		new Thread(ft, "返回结果的值").start();
    		try {
    			System.out.println(ft.get());
    		} catch (InterruptedException | ExecutionException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    	}
    }
    
    package demo2;
    
    import java.util.concurrent.Callable;
    import java.util.concurrent.FutureTask;
    
    public class CallableDemo implements Callable<Integer>{
    	@Override
    	public Integer call() throws Exception {
    		System.out.println("开始运行一个线程");
    		for(int i = 1; i < 10; i++) {
    			System.out.println("运行中");
    		}
    		return 1;	// 返回线程的值
    	}
    }
    
    在无知的道路上缓步前行
  • 相关阅读:
    iOS键盘监听事件
    JDBC中的Statement和PreparedStatement的区别 分类: JavaWeb 2014-05-18 13:46 5255人阅读 评论(2) 收藏
    Android中的隐藏API和Internal包的使用之获取应用电量排行 分类: Android 2014-05-16 17:55 3874人阅读 评论(4) 收藏
    Android中怎么破解游戏之修改金币数 分类: Android 2014-05-14 18:27 4802人阅读 评论(8) 收藏
    Android中通过反射来设置Toast的显示时间 分类: Android 2014-05-11 13:14 3291人阅读 评论(4) 收藏
    MySql中的变量定义 分类: Java 2014-05-04 10:41 6507人阅读 评论(0) 收藏
    MySql中创建存储过程 分类: Java 2014-05-04 10:31 4711人阅读 评论(1) 收藏
    MySQL数据库事务隔离级别(Transaction Isolation Level) 2014-05-04 09:52 4407人阅读 评论(0) 收藏
    C++中的static关键字 分类: Android 2014-04-22 13:45 448人阅读 评论(0) 收藏
    Android实现通过浏览器点击链接打开本地应用(APP)并拿到浏览器传递的数据 分类: Android 2014-04-17 16:15 11412人阅读 评论(18) 收藏
  • 原文地址:https://www.cnblogs.com/melovemingming/p/9986464.html
Copyright © 2011-2022 走看看