java基础

1.基础

1.1数据类型

存储范围

Boolean 和 double

1.2 object 类

方法

常用的11中方法

方法说明
public string tostring ()返回该对象的字符串表示
hashcode()native 方法用于返回对象的哈希码
equal方法默认地址比较相当于==,重写比较内容
class getClass()

getClass()方法是获得调用该方法的对象的类;getClass().getName()可以得到该类的路径;

(2)通过getClass()方法得到该对象类Class后,可以通过Class获取这个类中的相关属性和方法;

object clone()

深克隆:复制对象复制一份权限的,属性内容一致的对象 但是内存中的地址不一样

浅克隆:复制引用

void finalize()gc垃圾回收机制 

wait(long timeout)

不能重写 释放了锁,timeout是等待wait
wait(long timeout,int nanos)
wait()一直等待没有超时概念
notify()不能重写 唤醒一个等待的线程
notifyall()不能重写 唤醒所有等待的线程

hashcode

计算对象的散列值 返回int类型数据

对有散列表(hashmap,hashtable。。)的类有作用,比如hash set 插入数据时 可以直接通过hashcode去插入数据 不用一个个比较是否有重复

值相等 hashcode 一定相同 ,反之则未必

与equals的关系是 equals需要重写时 hashcode也许呀重写,否则会出现值相同但是hashcode 不相同的情况

equals 和==

==:引用数据类型 比较的是地址,基本数据类型比较的是值

equals没有重写等同于==,string 重写了equals 所以比较的是值

1.3 string  stringBuilder stringbuffer

string 是不可变的 ,因为string类中使用了final关键字修饰不能被继承,避免子类破坏string不可变,并且保存的char数组也被private final修饰为私有切不可变

stringbuilder 是可变的 继承自abstractstringbuilder 非线程安全的没有对方法加同步锁

stringbuffer是线程安全的,可变的,abstractstringbuilder提供了一些append,expandcapacity,insert ,indexof等方法

string适合操作少量的数据

string buffer适合操作多线程的大量数据

string builder 适合读操作单线程大量数据

string的intern方法是一个native 方法 作用是加那个指定的字符串对象的引用保存在字串常量池中

如果字符串常量池中保存了对应的字符串对象的引用,就直接返回该引用,

如果字符串常量池中保存了对应的字符串对象的引用,那就在常量池中创建一个指向该字符串对象的引用并返回

2.jdk源码

2.1 hashmap

阅读源码,了解hashmap数据结构

存放键值对,基于hash表map的接口试下  非线程安全

可以存储null 的key 和value  ,key只有一个null, 但是value 可以存多个null

jdk1.8之前由数组链表组成 数组是hashmap的主体,链表是为了解决hash冲突的,

1.8以后 在解决hash冲突是有了较大的变化 ,当链表长度大于等于阈值(默认为8),将链表转为红黑树,以减少搜索时间,在转红黑树之前会判断,如果当前的数组长度小于64,会选择对数组进行扩容

默认初始化大小为16,每次扩为2倍,hashmap总是使用2 的幂作为哈希表的大小

底层结构

1.8之前是数据加链表的组合,hashmap通过key的hashcode 经过扰动函数得到hash值 ,然后通过(n-1)&hash 判断当前元素的存放位置,如果当前位置存在的化,就判断是key和值相同,相同则覆盖 ,不相同则通过拉链法解决冲突

拉链法就是:链表数组组合,数组中每一格就是一个链表,遇到哈希冲突,将冲突的值加到链表中

1.8 的hash方法比1.7的简便

1.8 以后的在解决哈希冲突上有了较大的变化,当链表长度大于阈值8,首先会调用treeifbin方法,这个方法会根据hashmap数组来决定是否转为红黑树,只有当数组长度大于或者等与64的情况下,才会执行红黑树的操作,以减少搜素时间,否则就是执行resize方法来对数组扩容

扩容方式

hashmap底层有数组+链表(红黑树),数组大小可以在构造方法时设置,默认大小为16,,数组中每一个元素是一个链表,1.7采用头插法,1.8采用尾插法,插入的元素多了查找的效率就变低,所以满足一定条件链表就会转为红黑树,随着元素的增加,hashmap的数组会频繁扩容,如果构造时没有给加载因子设值,默认是0.75:

当添加某个元素后,数组的总添加元素树大于了数组长度×0.75,数组长度扩容为两倍,元素重新进入hashmap

如果没有红黑树,数组已经到64,链表也到8,再添加元素会转为红黑树

2.2 线程池

由于创建对象、连接、线程等操作时是比较“重”的,耗时的,高成本的。针对与这种场景,我们都会采用能复用就复用,而不是每次都要重新的去创建一遍

阅读源码

2.3Reentrantlook 

源码

和synchornized的区别

2.4 concurrent 并发包下源码

3.多线程

3.1多线程实现方式

继承thread类

package com.yjm.javalearning.practiceschedule.thread.createthread;

/**
 * @author77918
 * @namepractice-schedule
 * @date20232023/6/1723:56
 */
public class MyThread extends  Thread {

    public  void  run (){

        for(int i=0;i<100;i++){

            System.out.println(getName()+"hello");
        }
    }

}
package com.yjm.javalearning.practiceschedule.thread.createthread;

/**
 * @author77918
 * @namepractice-schedule
 * @date20232023/6/180:16
 */
public class ThreadDemo1 {
    public static void main(String[] args) {
        MyThread thread1= new MyThread();
        MyThread thread2= new MyThread();

        thread1.setName("first");
        thread2.setName("second");

        thread1.start();
        thread2.start();

    }
}

实现runnable接口

package com.yjm.javalearning.practiceschedule.thread.createthread;

/**
 * @author77918
 * @namepractice-schedule
 * @date20232023/6/182:08
 */
public class MyRun implements  Runnable {
    @Override
    public void run() {
        for (int i= 0;i<100;i++){
            Thread t= Thread.currentThread();
            System.out.println(t.getName()+"hello");
        }
    }
}
public class ThreadDemo1 {
    public static void main(String[] args) {
      /*  MyThread thread1= new MyThread();
        MyThread thread2= new MyThread();
*/

        MyRun mr=new MyRun();
        Thread thread1=new Thread(mr);
        Thread thread2=new Thread(mr);

        thread1.setName("first");
        thread2.setName("second");

        thread1.start();
        thread2.start();

    }
}

利用callable接口 和future接口实现方式

重写call方法

package com.yjm.javalearning.practiceschedule.thread.createthread;

import java.util.concurrent.Callable;

/**
 * @author77918
 * @namepractice-schedule
 * @date20232023/6/182:37
 */
public class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        int sum=0;
        for(int i=0;i<100;i++){
            sum=sum+i;
            
        }
        return sum;
    }
}
package com.yjm.javalearning.practiceschedule.thread.createthread;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @author77918
 * @namepractice-schedule
 * @date20232023/6/180:16
 */
public class ThreadDemo1 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
      /*  MyThread thread1= new MyThread();
        MyThread thread2= new MyThread();
*/

     /*   MyRun mr=new MyRun();
        Thread thread1=new Thread(mr);
        Thread thread2=new Thread(mr);*/


       MyCallable mc= new MyCallable();
       FutureTask<Integer> futureTask= new FutureTask<>(mc);
       Thread thread1=new Thread(futureTask);

        thread1.setName("first");


        thread1.start();

        Integer result = futureTask.get();
        System.out.println(result);
    }
}

小结

实现类的优点 编程简单可以可以直接使用thread 类中方法 但是不能在去继承其他类,扩展性差

接口不可以直接使用thread类中的方法  但是扩展性好

常见的成员方法

方法名称说明
String getName()返回此线程的名称
void setName(String name)设置线程的名字
static Thread currentThread()获取当前线程的对象
static void sleep(long time)设置线程休眠指定时间 单位毫秒
setPriority(int newPriority)设置线程的优先级
final int getPriority()获取线程的优先级
final void setDaemon(boolean on)设置守护线程
public static void yield()出让线程
public static void join()插队线程

线程优先级1-10  默认是5

守护线程:当其他非守护线程执行结束 守护线程也会陆续结束

保证线程安全

同步代码块

锁对象一定是唯一的

synchronized 加在循环里面

package com.yjm.javalearning.practiceschedule.thread.createthread;

/**
 * @author77918
 * @namepractice-schedule
 * @date20232023/6/1723:56
 */
public class MyThread extends  Thread {
//这个类的所有对象都共享ticket数据
static int ticket =0;
//锁对象 必须是唯一的
static Object obj= new Object();
    @Override
    public  void  run (){

       while (true){
         synchronized (obj){
             if(ticket<100){
                 try {
                     Thread.sleep(100);
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 } ticket++;
                 System.out.println(getName()+"第"+ticket);
             }else {
                 break;
             }
         }
       }
    }

}

同步方法

同步方法是所著方法里的所有代码 且锁对象不能自己指定

就是把之前方法块里 的抽出来做方法

package com.yjm.javalearning.practiceschedule.thread.createthread;

/**
 * @author77918
 * @namepractice-schedule
 * @date20232023/6/182:08
 */
public class MyRun implements  Runnable {
    // ticket 只创建一次 所以不需要加上static
    int ticket =0;

    @Override
    public  void  run (){

        while (true){
            synchronized (MyThread.class) {
             if (method()) break;
            }
        }
    }

    
    private boolean method(){
        if (ticket < 100) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ticket++;
            System.out.println(Thread.currentThread().getName() + "第" + ticket);
        } 
        return false;
    }
    
}

Lock锁

lock锁实现提供比使用synchronized方法和语句可以获得更广泛的锁定操作 

提供了获得锁和释放锁的方法:

获得锁 void  lock(),释放锁 void unlock()

lock是不能直接实例化,采用lock的实现类 ReentrantLock来实例化

Reentrant Lock():构造方法  创建一个reentranlock实例 

要保证锁一定会被释放

package com.yjm.javalearning.practiceschedule.thread.createthread;

import ch.qos.logback.core.joran.conditional.ElseAction;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author77918
 * @namepractice-schedule
 * @date20232023/6/182:08
 */
public class MyRun implements  Runnable {
    // ticket 只创建一次 所以不需要加上static
    int ticket =0;
    
    static Lock lock=new ReentrantLock();
    @Override
    public  void  run (){

        while (true){
           lock.lock();
               
                    try {
                        if (ticket == 100) {
                            break;
                        } else {
                            Thread.sleep(100);

                            ticket++;
                            System.out.println(Thread.currentThread().getName() + "第" + ticket);
                        }
                    } catch (InterruptedException e) {
                            e.printStackTrace();
                        }finally{
                            lock.unlock();
                        }
                    
                }
            
        }
    }


    


生产者和消费者问题

多线程同步的经典问题 ,生产者生产一定的数据放到缓冲池区,消费者也在缓冲区消耗这些数据 ,生产者和消费者之间必须保证同步 ,保证缓冲区满了的时候 生产者不会在缓冲区放入数据,缓冲区空的时候消费者不会去消费数据

notify()/wait()

常见方法 :void waite(),void notify(),void notifyall()

思路:当缓冲区满了,生产者线程停止执行,放弃锁,生产者处于等待,当缓冲区已空,消费者停止执行,放弃锁,进入等待状态

仓库:

package com.yjm.javalearning.practiceschedule.thread.createthread.ProducerConsumer;

import java.util.LinkedList;

/**
 * @author77918
 * @namepractice-schedule
 * @date20232023/6/1813:59
 */
public class Storage {

    private final  int MAX_SIZE=10;
     private LinkedList<Object> list =new LinkedList<>();

     public void produce(){
         synchronized (list){
             while (list.size()+1>MAX_SIZE){
                 System.out.println("【producer"+Thread.currentThread().getName()+"】仓库已满");

                 try {
                     list.wait();
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
             list.add(new Object());
             System.out.println("【producer"+Thread.currentThread().getName()+"】生产一个产品,当下库存为::"+list.size());
             list.notifyAll();
         }
     }

     public void consume(){
         synchronized (list){
             while (list.size()==0){
                 System.out.println("【consume"+Thread.currentThread().getName()+"】库存为空");

                 try {
                     list.wait(1000);
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
             list.remove();
             System.out.println("【consume"+Thread.currentThread().getName()+"】消费一个产品,现在库存“:"+list.size());
             list.notifyAll();
         }

     }

}

生产者 

package com.yjm.javalearning.practiceschedule.thread.createthread.ProducerConsumer;

/**
 * @author77918
 * @namepractice-schedule
 * @date20232023/6/1813:58
 */
public class Producer implements  Runnable {


    private   Storage storage;

    public Producer() {
    }

    public Producer(Storage storage) {
        this.storage=storage;
    }

    @Override
    public void run() {
        while (true){
            try {
                Thread.sleep(1000);
                storage.produce();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

消费者 

package com.yjm.javalearning.practiceschedule.thread.createthread.ProducerConsumer;

/**
 * @author77918
 * @namepractice-schedule
 * @date20232023/6/1814:02
 */
public class Consumer implements Runnable {

    private   Storage storage;

    public Consumer() {
    }
    public Consumer(Storage storage) {
        this.storage=storage;
    }
    @Override
    public void run() {
      while (true){
          try {
              Thread.sleep(3000);
              storage.consume();
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
      }
    }
}

测试类

package com.YJM.love.com.YJM.test;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

/**
 * @author77918
 * @namelove_take_out
 * @date20232023/6/151:22
 */
public class Task1 {
    public static void main(String[] args) {
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:MM:ss.SSS");
                String datestr= simpleDateFormat.format(new Date());
                System.out.println("定时任务"+datestr);

            }
        };
        //计时器
        Timer timer = new Timer();
        //添加执行任务 延迟1s执行,每3s执行一次
        timer.schedule(timerTask,1000,3000);

    }
}

await()/signal()

在jdk5中 用reentrantlock 和condition可以实现等待/通知模型 ,更灵活,通过在lock对象上调用new condition方法,将变量和锁对象进行帮电工,进而控制并发程序访问竞争资源的安全

package com.yjm.javalearning.practiceschedule.thread.createthread.ProducerConsumer;

import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author77918
 * @namepractice-schedule
 * @date20232023/6/1813:59
 */
public class Storage {

    private final  int MAX_SIZE=10;
     private LinkedList<Object> list =new LinkedList<>();
     //锁
     private final Lock lock=new ReentrantLock();
     //仓库满的条件变量
    private  final Condition full =lock.newCondition();
    //仓库空的条件变量
    private  final  Condition empty=lock.newCondition();

     public void produce(){
         lock.lock();
             while (list.size()+1>MAX_SIZE){
                 System.out.println("【producer"+Thread.currentThread().getName()+"】仓库已满");

                 try {
                   full.await();
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
             list.add(new Object());
             System.out.println("【producer"+Thread.currentThread().getName()+"】生产一个产品,当下库存为::"+list.size());
            empty.signalAll();
            lock.unlock();

     }

     public void consume(){
       lock.lock();
             while (list.size()==0){
                 System.out.println("【consume"+Thread.currentThread().getName()+"】库存为空");

                 try {
                     empty.await(1000);
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
             list.remove();
             System.out.println("【consume"+Thread.currentThread().getName()+"】消费一个产品,现在库存“:"+list.size());
          full.signalAll();
           lock.unlock();


     }

}

blockingqueue阻塞队列

在内部实现同步的队列 

实现方式采用 await() signal()

可以在生成对象时指定容量大小  用于阻塞操作的是put 和take方法

put():生产者容量达到最大时 阻塞

take():消费者容量到达最大时阻塞

package com.yjm.javalearning.practiceschedule.thread.createthread.ProducerConsumer;

import java.util.LinkedList;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author77918
 * @namepractice-schedule
 * @date20232023/6/1813:59
 */
public class Storage {

     
     private LinkedBlockingQueue<Object> list =new LinkedBlockingQueue<>(10);
     

     public void produce(){

         try {
             list.put(new Object());
             System.out.println("【producer"+Thread.currentThread().getName()+"】生产一个产品,当下库存为::"+list.size());

         } catch (InterruptedException e) {
             e.printStackTrace();
         }
      

     }

     public void consume(){
         try {
             list.take();
             System.out.println("【consume"+Thread.currentThread().getName()+"】消费一个产品,现在库存“:"+list.size());


         } catch (InterruptedException e) {
             e.printStackTrace();
         }
        

     }

}

信号量

semaphore是一种基于计数的信号量,可以设定一个阈值,基于此 多个线程竞争获取许可信号,实现后归还信号,超过阈值 线程申请许可信号将会被阻塞 ,可以创建计数为1的,将其作为一种类似互斥锁的机制, 也叫二元信号量,表示两种互斥状态,计数为0 表示基于release,然后就可以acquire

package com.yjm.javalearning.practiceschedule.thread.createthread.ProducerConsumer;

import java.util.LinkedList;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author77918
 * @namepractice-schedule
 * @date20232023/6/1813:59
 */
public class Storage {


     private LinkedList<Object> list =new LinkedList<>();
     //仓库最大容量
      final Semaphore notfull= new Semaphore(10);
      //将线程挂起,等待其他线程来触发
      final Semaphore notempty=new Semaphore(0);
      //互斥锁
      final Semaphore mutex=new Semaphore(1);
      

     public void produce(){

         try {
             notfull.acquire();
             mutex.acquire();
             list.add(new Object());
             System.out.println("【producer"+Thread.currentThread().getName()+"】生产一个产品,当下库存为::"+list.size());

         } catch (InterruptedException e) {
             e.printStackTrace();
         }finally {
             mutex.release();
             notempty.release();
         }


     }

     public void consume(){
         try {
             notempty.acquire();
             mutex.acquire();
             list.remove();
             
             System.out.println("【consume"+Thread.currentThread().getName()+"】消费一个产品,现在库存“:"+list.size());


         } catch (InterruptedException e) {
             e.printStackTrace();
         }finally {
             mutex.release();
             notfull.release();
         }
        

     }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值