多线程
1.继承Thread类
- start和主线程同时执行,run只是顺序执行一遍方法
- 进程调度执行,每次结果不一样
@Override
public void run(){
for(int i=0;i<20;i++){
System.out.println("看代码"+i);
}
}
public static void main(String[] args){
Test01 thread01=new Test01();
thread01.start();
for(int i=0;i<20;i++){
System.out.println("我在学习多线程"+i);
}
}
2.继承Runnable接口
//创建方式2:用Runnable接口,重写run方法
public class Test02 implements Runnable {
@Override
public void run(){
for(int i=0;i<20;i++){
System.out.println("看代码"+i);
}
}
public static void main(String[] args){
Test02 thread02=new Test02();
//代理
new Thread(thread02).start();
for(int i=0;i<20;i++){
System.out.println("我在学习多线程"+i);
}
}
}
- 小结
3.抢票
public class Test03 implements Runnable {
private int tickNum=10;
@Override
public void run(){
while (true){
if(tickNum<=0){
break;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->拿到了第"+tickNum--+"票");
}
}
public static void main(String[] args){
Test03 ticket=new Test03();
new Thread(ticket,"小明").start();
new Thread(ticket,"老师").start();
new Thread(ticket,"黄牛").start();
}
}
- 问题 并发问题,同一时刻多个对象操作一个资源,导致抢到的票号相同
4.实现Callable接口
5.静态代理
-
代理对象和真实对象需要实现同一个接口
-
代理需要代理一个真实角色
-
好处,代理对象可以帮忙做很多事情,真实对象只需要专注做自己的事情
6.Lamdab表达式
7.线程状态
8.线程停止
//测试Stop
//1.建议线程正常日内告知-->利用次数,不建议死循环
//2.建议使用标志位-->设置一个标志位
//3.不要使用stop或者destory等过失或者JDK不建议的方法
public class TestStop implements Runnable{
private boolean flag=true;
@Override
public void run() {
int i=0;
while (flag){
System.out.println("run-----Thread:"+i++);
}
}
private void stop() {
this.flag=false;
}
public static void main(String[] args) {
TestStop testStop=new TestStop();
new Thread(testStop).start();
for (int i=0;i<1000;i++){
System.out.println("Main"+i++);
if(i>=900){
testStop.stop();
System.out.println("线程停止了");
}
}
}
}
9.线程休眠
- 模拟倒计时
- 模拟强抢票
public class TestSleep implements Runnable{
private int tickNum=10;
@Override
public void run(){
while (true){
if(tickNum<=0){
break;
}
//模拟网络延迟,放大问题的发生性
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->拿到了第"+tickNum--+"票");
}
}
public static void main(String[] args){
TestSleep ticket=new TestSleep();
new Thread(ticket,"小明").start();
new Thread(ticket,"老师").start();
new Thread(ticket,"黄牛").start();
}
}
- Sleep制定当前线程阻塞毫秒数
- 存在异常interruptedException
- Sleep时间到达后线程进入就绪状态
- sleep模拟网络延时,倒计时
- 每个对象都有一个锁,sleep不会释放锁
10.线程礼让
- 让正在执行的线程暂停,但不阻塞
- 让CPU重新调度,但礼让不一定成功
//测试礼让,不一定成功
public class TestYiled {
public static void main(String[] args) {
Myyiled myyiled=new Myyiled();
new Thread(myyiled,"a").start();
new Thread(myyiled,"b").start();
}
}
class Myyiled implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"线程开始执行");
Thread.yield();
System.out.println(Thread.currentThread().getName()+"线程停止执行");
}
}
11.线程强制执行
//jpin 方法
public class TestJoin implements Runnable{
@Override
public void run() {
for (int i=0;i<1000;i++){
System.out.println("线程插队"+i);
}
}
public static void main(String[] args) throws InterruptedException {
TestJoin testJoin=new TestJoin();
Thread thread=new Thread(testJoin);
thread.start();
for (int i=0;i<500;i++){
if(i==200){
thread.join();
}
System.out.println("主线程"+i);
}
}
}
12.观察线程状态
public class TestState {
public static void main(String[] args) throws InterruptedException {
Thread thread=new Thread(()->{
for (int i=0;i<5;i++){
try {
Thread.sleep(1000);
System.out.println("run"+i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("///");
});
//观察状态
Thread.State state=thread.getState();
System.out.println(state);//new
//观察启动后
thread.start();
state=thread.getState();
System.out.println(state);//Run
while (state!=Thread.State.TERMINATED){
Thread.sleep(1000);
state=thread.getState();
System.out.println(state);
}
}
}
- 死亡之后的线程无法再启动
- 不能启动两次
13.线程优先级
//线程优先级
public class TestPriority {
public static void main(String[] args) {
//主线程优先级
System.out.println(Thread.currentThread().getName()+"->"+Thread.currentThread().getPriority());
Mypriority mypriority=new Mypriority();
Thread t1=new Thread(mypriority);
Thread t2=new Thread(mypriority);
Thread t3=new Thread(mypriority);
Thread t4=new Thread(mypriority);
Thread t5=new Thread(mypriority);
Thread t6=new Thread(mypriority);
//先设置优先级,在启动
t1.start();//默认为5
t2.setPriority(1);
t2.start();
t3.setPriority(4);
t3.start();
t4.setPriority(Thread.MAX_PRIORITY);//10
t4.start();
t5.setPriority(8);
t5.start();
t6.setPriority(7);
t6.start();
}
}
class Mypriority implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"->"+Thread.currentThread().getPriority());
}
}
- 注意先设置优先级在启动
- 优先级高的先执行概率高,但不是百分百
- 默认优先级为5
14.守护线程
- 线程分为用户线程和守护线程
- 虚拟机必须确保用户线程执行完毕,Main
- 虚拟机不用等待守护线程执行完毕,GC
- 如后台记录操作日志,监控内存,垃圾回收
public class TestDaemon {
public static void main(String[] args) {
God god=new God();
You you=new You();
Thread thread=new Thread(god);
thread.setDaemon(true);//默认是false用户西安城,正常的线程都是用户线程
thread.start();//上帝线程开启
new Thread(you).start();//用户线程开启
}
}
class God implements Runnable{
@Override
public void run() {
while (true){
System.out.println("上帝守护");
}
}
}
class You implements Runnable{
@Override
public void run() {
for (int i = 0; i <36500 ; i++) {
System.out.println("你 活着"+i);
}
}
}
- 守护线程不会关闭
线程同步
-
多线程操作同一个对象,并发,需要同步解决
-
解决线程排队,保证安全加锁
-
锁会损失性能,性能倒置问题
1.线程不安全
- 不安全买票,有负数
- 不安全取钱,两个人去取钱,sleep方法问题发生性
- 线程不安全集合,ArryList,同一瞬间,两个线程给一个索引list【i】添加数据,其中一个数据被覆盖了
2.同步方法和同步块
- synchronized 关键字
- 方法加上就成为同步方法,控制对象的访问,给每个对象加上一把锁
- 只有获得对象的锁才能执行,否则会线程阻塞,一旦执行就会独占该锁,方法结束会释放锁
- 方法设置synchronized 缺陷影响效率
- 锁多了会浪费性能
public class Test03 implements Runnable {
private int tickNum=10;
@Override
//这里所得是this
public synchronized void run(){
//加上锁之后就可以保证线程安全
while (true){
if(tickNum<=0){
break;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->拿到了第"+tickNum--+"票");
}
}
public static void main(String[] args){
Test03 ticket=new Test03();
new Thread(ticket,"小明").start();
new Thread(ticket,"老师").start();
new Thread(ticket,"黄牛").start();
}
}
- synchronized 默认锁的是对象
- 同步块
- 锁得对象是变化的量,增删改
3.线程安全的集合
- 并发里面的
//测试JUC安全类型的集合
public class TestJUC {
public static void main(String[] args) throws InterruptedException {
CopyOnWriteArrayList<String> list=new CopyOnWriteArrayList<>();
for (int i = 0; i <10000 ; i++) {
new Thread(()->{
list.add(Thread.currentThread().getName());
}).start();
}
Thread.sleep(3000);
System.out.println(list.size());
}
}
4.死锁
- 死锁,多个线程需要资源,相互等待僵持
5.Lock
public class TestLock {
public static void main(String[] args) {
TestLock2 testLock2=new TestLock2();
new Thread(testLock2).start();
new Thread(testLock2).start();
new Thread(testLock2).start();
}
}
class TestLock2 implements Runnable{
int tickeNum=10;
//定义可重入锁lock
private final ReentrantLock lock=new ReentrantLock();
@Override
public void run() {
while (true){
try {
lock.lock();//加锁
if(tickeNum>0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(tickeNum--);
}else {
break;
}
}finally {
lock.unlock();//解锁
}
}
}
}
7.生产者消费者
8.管程法
//生产者消费者模型-》利用缓冲区解决:管程法
public class TestPC {
public static void main(String[] args) {
SynContainer container=new SynContainer();
new Productor(container).start();
new Consumer(container).start();
}
}
//生产者
class Productor extends Thread{
SynContainer container;
public Productor(SynContainer container) {
this.container = container;
}
//生产
@Override
public void run() {
for (int i = 0; i <100; i++) {
System.out.println("生产鸡"+i);
container.push(new Chicken(i));
}
}
}
//消费者
class Consumer extends Thread {
SynContainer container;
public Consumer(SynContainer container) {
this.container = container;
}
//消费
@Override
public void run() {
for (int i = 0; i <100; i++) {
System.out.println("消费了鸡->"+container.pop().id);
}
}
}
//产品
class Chicken{
int id;
public Chicken(int id) {
this.id = id;
}
}
//缓冲区
class SynContainer{
//定义容器大小
Chicken[] chickens=new Chicken[10];
int count=0;
//生产者放入产品
public synchronized void push(Chicken chicken){
//容器满了等待消费者消费
if(count==chickens.length){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
//通知消费者消费,等待生产
}
//如果没有满,丢入产品
chickens[count]=chicken;
count++;
//可以通知消费者消费
this.notifyAll();
}
//消费者消费产品
public synchronized Chicken pop(){
//判断能否消费
if(count==0){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
//等待生产者生产,消费者消费
}
//可以消费
count--;
Chicken chicken=chickens[count];
//吃完通知生产者生产
this.notifyAll();
return chicken;
}
}
9.信号灯法
- 通过标值位解决
- TODO
10.线程池
//测试线程池
public class TestPool {
public static void main(String[] args) {
//1.创建服务,创建线程池
//参数位线程池大小
ExecutorService service= Executors.newFixedThreadPool(10);
//执行
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
//2.关闭连接
service.shutdown();
}
}
class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
注解和反射
1.内置注解
- 系统内置的注解
2.元注解
- 解释其他注解的注解
3.自定义注解
import java.lang.annotation.*;
//测试元注解
@MyAnootation
public class Test01 {
@MyAnootation
public void test(){
}
}
//定义一个元注解,约束再方法上,类上
//Target 表示注解作用的范围
@Target(value ={
ElementType.METHOD,ElementType.TYPE})
//Retention 生效的时间,这里是运行还生效
//runTime>class>sources
@Retention(value = RetentionPolicy.RUNTIME)
//表示能否将注解生成再JAVAdoc中
@Documented
//Inherited 子类可以继承父类注解
@Inherited
@interface MyAnootation{
}
public class Test02 {
//注解可以被赋值,如果没有默认值则必须赋值,顺序随意
@MyAnootation2(age=11,name = "小明",id = 20)
public void test(){
}
}
@Target(value = {
ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnootation2{
//注解的参数,参数类型+参数名()
String name() default "";
int age();
int id() default -1;//默认值为-1.表示不存在
String[] school() default {
"山东大学","西北大学"};
}
- 只有一个值的时候,参数名需要些value(也是默认的),传参的时候可以不用写参数名
4.反射
- 动态语言 运行时可以改变结构的语言,例如新函数,对象,甚至代码
- 主要语言:Object-C,C#,Javascript,PHP,Python
- 静态语言 运行时结构不可变的语言
- 如JAVA ,C,C++
- Java不是动态语言,可以成为”准动态语言“,有一定的动态性,用反射机制可以获得类似动态语言的恶行的特性
//什么叫反射
public class Test01 {
public static void main(String[] args) throws ClassNotFoundException {
//通过反射获取类的Class对象
Class<?> c1=Class.forName("com.cheng.Reflection.User");
Class<?> c2=Class.forName("com.cheng.Reflection.User");
//hashcode值一样表示是同一个类,一个类在内存中只有一个Class
//一个类被加载后,整个类的结构都会被封装再Class对象中
System.out.println(c1.hashCode());
System.out.println(c2.hashCode());
}
}
//实体类,只有属性
class User{
private String name;
private int id;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id=" + id +
", age=" + age +
'}';
}
}
5.得到反射的类型
package com.cheng.Reflection;
//测试Class创建方式
public class Test02 {
public static void main(String[] args) throws ClassNotFoundException {
Person person=new Student();
System.out.println("这个人是:"+person.name);
//方式一:通过对象获得
Class c1=person.getClass();
System.out.println(c1.hashCode());
//方式二:forname获得
Class c2=Class.forName("com.cheng.Reflection.Student");
System.out.println(c2.hashCode());
//方式三:通过类名.class获得
Class c3=Student.class;
System.out.println(c3.hashCode());
//方法四:;基本类型的包装类都有一个Type属性
Class c4=Integer.TYPE;
System.out.println(c4);
//获得父类类型
Class c5=c1.getSuperclass();
System.out.println(c5+","+c5.hashCode());
}
}
class Person{
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
class Student extends Person{
public Student(){
this.name="学生";
}
}
class Teacher extends Person{
public Teacher(){
this.name="老师";
}
}
6.所有类型的Class对象
//所有类型的Class
public class Test04 {
public static void main(String[] args) {
Class c1=Object.class;//类
Class c2=Comparable.class;//接口
Class c3=String[].class;//一维数组
Class c4=int[][].class;//二维数组
Class c5=Override.class;//注解
Class c6= ElementType.class;//枚举
Class c7=Integer.class;//基本数据类型
Class c8=void.class;//void
Class c9=Class.class;//Class
System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
System.out.println(c4);
System.out.println(c5);
System.out.println(c6);
System.out.println(c7);
System.out.println(c8);
System.out.println(c9);
}
}
- 只要元素类型与维度一样就是一个Class
7.类加载内存分析
//类是如何被加载的
public class Test05 {
public static void main(String[] args) {
A a=new A();
System.out.println(A.m);//100
//A类静态代码块初始化
//A类无参构造器初始化
//100
}
}
class A{
static{
System.out.println("A类静态代码块初始化");
m=300;
}
static int m=100;
public A(){
System.out.println("A类无参构造器初始化");
}
}
//类是如何被加载的
public class Test05 {
public static void main(String[] args) {
A a=new A();
System.out.println(A.m);//100
/*
* 1.加载到内存,产生一个类对对应的class对象
* 2.链接,链接结束后m=0;
* 3.初始化
* <clint>(){
* System.out.println("A类静态代码块初始化");
m=300;
m=100;
*
* }
*/
}
}
class A{
static{
System.out.println("A类静态代码块初始化");
m=300;
}
static int m=100;
public A(){
System.out.println("A类无参构造器初始化");
}
}
8.类初始化
public class Test06 {
static {
System.out.println("Main类加载");
}
public static void main(String[] args) throws ClassNotFoundException {
//主动引用
//Son son=new Son();
//Main类加载
//父类被加载
//子类被加载
//反射也会产生主动引用
//Class.forName("com.cheng.Reflection.Son");
//不会产生类的引用的方法
//System.out.println(Son.b);//这里父类不加载。子类不架子啊
//Son[] arry=new Son[5];//只是命名和开辟空间,不做初始化
System.out.println(Son.M);//常量,父类子类都没加载
}
}
class Father{
static int b=2;
static {
System.out.println("父类被加载");
}
}
class Son extends Father{
static int m=100;
static final int M=1;
static {
System.out.println("子类被加载");
m=300;
}
}
9.类加载器
//类加载器
public class Test07 {
public static void main(String[] args) throws ClassNotFoundException {
//获取系统类加载器
ClassLoader systemClassLoader=ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);
//获取系统类加载器加载器-》扩展加载器
ClassLoader parent=systemClassLoader.getParent();
System.out.println(parent);
//获取扩展类加载器的父类加载器-》根加载器(C/C++)
ClassLoader root=parent.getParent();
System.out.println(root);//无法直接获取
//测试当前类是哪个类加载的
ClassLoader classLoader=Class.forName("com.cheng.Reflection.Test07").getClassLoader();
System.out.println("Test07"+classLoader);//用户自定义类AppClassLoader
//测试JDK内置的类是谁加载的
classLoader=Class.forName("java.lang.Object").getClassLoader();
System.out.println("Object"+classLoader);//根加载器
//如何获得系统类加载器可以加载的路径
System.out.println(System.getProperty("java.class.path"));
//双亲委派机制,会向上找包
}
}
10.反射获取类的运行结构
//获取类的信息
public class Test08 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class c1=Class.forName("com.cheng.Reflection.User");
//获取类名
System.out.println(c1.getName());//获得包名和类名
System.out.println(c1.getSimpleName());//类名
//获得类的属性
Field[] fields=c1.getFields();//只能找到public属性
for (int i = 0; i < fields.length; i++) {
System.out.println(fields[i]);
}
fields=c1.getDeclaredFields();//可以所有属性
for (int i = 0; i < fields.length; i++) {
System.out.println(fields[i]);
}
//获得指定属性的值
System.out.println("=======================================");
Field name=c1.getDeclaredField("name");
System.out.println(name);
//获得类的方法
Method[] methods= c1.getMethods();//本类及其父类全部public方法
for (Method method : methods) {
System.out.println("正常的"+method);
}
methods= c1.getDeclaredMethods();//获得本类所有方法
for (Method method : methods) {
System.out.println("Declared"+method);
}
//获得指定方法
Method getName= c1.getMethod("getName",null);
Method setName= c1.getMethod("setName", String.class);//参数
System.out.println(getName);
System.out.println(setName);
//获得指定构造器
System.out.println("=======================================");
Constructor[] constructors=c1.getConstructors();//public
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
constructors=c1.getDeclaredConstructors();//全部
for (Constructor constructor : constructors) {
System.out.println("#"+constructor);
}
//获取指定构造器
Constructor decConstructor=c1.getDeclaredConstructor(int.class,String.class,int.class);//参数位置需要匹配
System.out.println("指定的"+decConstructor);
}
}
11.动态创建对象执行方法
//动态创建对象,通过反射
public class Test09 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//获得Class对象
Class c1=Class.forName("com.cheng.Reflection.User");
//构造一个对象
User user=(User)c1.newInstance();//本质调用无参构造器
System.out.println(user);
//通过构造器创建对象
Constructor constructor= c1.getDeclaredConstructor(int.class,String.class,int.class);
User user1=(User)constructor.newInstance(11,"夏美",18);//本质调用有参构造器
System.out.println(user1);
//通过反射调用普通方法
User user2=(User)c1.newInstance();
//通过反射获取一个方法,并激活
// invoke(对象,参数)
Method setName=c1.getDeclaredMethod("setName", String.class);
setName.invoke(user2,"云天明");
System.out.println(user2);
//反射操作属性
User user3=(User)c1.newInstance();
Field name=c1.getDeclaredField("name");
name.setAccessible(true);//关闭程序安全检查,可以操作私有属性
name.set(user3,"cheng");
System.out.println(user3.getName());
}
}
12.性能对比
- 普通方法
- 9ms
- 反射方法
- 5699ms
- 反射方法调用 关闭检测
- 1959ms
13.获取泛型信息
//通过反射获取泛型
public class Test10 {
public void test01(Map<String ,User>map, List<User> list){
System.out.println("test01");
}
public Map<String,User> test02(){
return null;
}
public static void main(String[] args) throws NoSuchMethodException {
Method method=Test10.class.getMethod("test01", Map.class, List.class);
//获得参数类型
Type[] genericParameter=method.getGenericParameterTypes();
for (Type type : genericParameter) {
System.out.println("#"+genericParameter);
//是否是参数化类型
if(type instanceof ParameterizedType){
//参数化类型
//获得真实的参数信息
Type[] actualType=((ParameterizedType) type).getActualTypeArguments();
for (Type type1 : actualType) {
System.out.println("#"+type1);
}
}
}
//方法二
Method method2=Test10.class.getMethod("test02",null);
//返回值类型
Type gennerType= method2.getGenericReturnType();
if(gennerType instanceof ParameterizedType){
//参数化类型
//获得真实的参数信息
Type[] actualType=((ParameterizedType) gennerType).getActualTypeArguments();
for (Type type1 : actualType) {
System.out.println("###"+type1);
}
}
}
}
14.获取注解信息
//通过反射操作注解
public class Test11 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class c1=Class.forName("com.cheng.Reflection.Student2");
//通过反射获得注解
Annotation[] annotations=c1.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);//db_Student,找到了外面的注解
}
//获得注解的value值
Tablecheng tablecheng=(Tablecheng)c1.getAnnotation(Tablecheng.class);
String value=tablecheng.value();
System.out.println(value);
//获得类指定的注解
Field f=c1.getDeclaredField("name");//name id age
Fieldcheng annotation=f.getAnnotation(Fieldcheng.class);
System.out.println(annotation.columnName());
System.out.println(annotation.type());
System.out.println(annotation.length());
}
}
@Tablecheng("db_Student")
class Student2{
@Fieldcheng(columnName="db_id",type = "int",length = 10)
private int id;
@Fieldcheng(columnName="db_age",type = "int",length = 10)
private int age;
@Fieldcheng(columnName="db_name",type = "varchar",length = 10)
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Student2(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "Student2{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}
//类名的注解
@Target({
ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface Tablecheng{
String value();
}
//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Fieldcheng{
String columnName();
String type();
int length();
}